diff options
201 files changed, 16473 insertions, 3893 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 0bbee38acd26..72aff61e7315 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
| @@ -753,8 +753,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 753 | 753 | ||
| 754 | [Multiple options for each card instance] | 754 | [Multiple options for each card instance] |
| 755 | model - force the model name | 755 | model - force the model name |
| 756 | position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) | 756 | position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) |
| 757 | probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) | 757 | probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) |
| 758 | bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. | ||
| 759 | Passing -1 will make the driver to choose the appropriate | ||
| 760 | value based on the controller chip. | ||
| 758 | 761 | ||
| 759 | [Single (global) options] | 762 | [Single (global) options] |
| 760 | single_cmd - Use single immediate commands to communicate with | 763 | single_cmd - Use single immediate commands to communicate with |
| @@ -845,7 +848,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 845 | ALC269 | 848 | ALC269 |
| 846 | basic Basic preset | 849 | basic Basic preset |
| 847 | 850 | ||
| 848 | ALC662 | 851 | ALC662/663 |
| 849 | 3stack-dig 3-stack (2-channel) with SPDIF | 852 | 3stack-dig 3-stack (2-channel) with SPDIF |
| 850 | 3stack-6ch 3-stack (6-channel) | 853 | 3stack-6ch 3-stack (6-channel) |
| 851 | 3stack-6ch-dig 3-stack (6-channel) with SPDIF | 854 | 3stack-6ch-dig 3-stack (6-channel) with SPDIF |
| @@ -853,6 +856,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 853 | lenovo-101e Lenovo laptop | 856 | lenovo-101e Lenovo laptop |
| 854 | eeepc-p701 ASUS Eeepc P701 | 857 | eeepc-p701 ASUS Eeepc P701 |
| 855 | eeepc-ep20 ASUS Eeepc EP20 | 858 | eeepc-ep20 ASUS Eeepc EP20 |
| 859 | m51va ASUS M51VA | ||
| 860 | g71v ASUS G71V | ||
| 861 | h13 ASUS H13 | ||
| 862 | g50v ASUS G50V | ||
| 856 | auto auto-config reading BIOS (default) | 863 | auto auto-config reading BIOS (default) |
| 857 | 864 | ||
| 858 | ALC882/885 | 865 | ALC882/885 |
| @@ -1091,7 +1098,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1091 | This occurs when the access to non-existing or non-working codec slot | 1098 | This occurs when the access to non-existing or non-working codec slot |
| 1092 | (likely a modem one) causes a stall of the communication via HD-audio | 1099 | (likely a modem one) causes a stall of the communication via HD-audio |
| 1093 | bus. You can see which codec slots are probed by enabling | 1100 | bus. You can see which codec slots are probed by enabling |
| 1094 | CONFIG_SND_DEBUG_DETECT, or simply from the file name of the codec | 1101 | CONFIG_SND_DEBUG_VERBOSE, or simply from the file name of the codec |
| 1095 | proc files. Then limit the slots to probe by probe_mask option. | 1102 | proc files. Then limit the slots to probe by probe_mask option. |
| 1096 | For example, probe_mask=1 means to probe only the first slot, and | 1103 | For example, probe_mask=1 means to probe only the first slot, and |
| 1097 | probe_mask=4 means only the third slot. | 1104 | probe_mask=4 means only the third slot. |
| @@ -2267,6 +2274,10 @@ case above again, the first two slots are already reserved. If any | |||
| 2267 | other driver (e.g. snd-usb-audio) is loaded before snd-interwave or | 2274 | other driver (e.g. snd-usb-audio) is loaded before snd-interwave or |
| 2268 | snd-ens1371, it will be assigned to the third or later slot. | 2275 | snd-ens1371, it will be assigned to the third or later slot. |
| 2269 | 2276 | ||
| 2277 | When a module name is given with '!', the slot will be given for any | ||
| 2278 | modules but that name. For example, "slots=!snd-pcsp" will reserve | ||
| 2279 | the first slot for any modules but snd-pcsp. | ||
| 2280 | |||
| 2270 | 2281 | ||
| 2271 | ALSA PCM devices to OSS devices mapping | 2282 | ALSA PCM devices to OSS devices mapping |
| 2272 | ======================================= | 2283 | ======================================= |
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index b03df4d4795c..e13c4e67029f 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | |||
| @@ -6127,8 +6127,8 @@ struct _snd_pcm_runtime { | |||
| 6127 | 6127 | ||
| 6128 | <para> | 6128 | <para> |
| 6129 | <function>snd_printdd()</function> is compiled in only when | 6129 | <function>snd_printdd()</function> is compiled in only when |
| 6130 | <constant>CONFIG_SND_DEBUG_DETECT</constant> is set. Please note | 6130 | <constant>CONFIG_SND_DEBUG_VERBOSE</constant> is set. Please note |
| 6131 | that <constant>DEBUG_DETECT</constant> is not set as default | 6131 | that <constant>CONFIG_SND_DEBUG_VERBOSE</constant> is not set as default |
| 6132 | even if you configure the alsa-driver with | 6132 | even if you configure the alsa-driver with |
| 6133 | <option>--with-debug=full</option> option. You need to give | 6133 | <option>--with-debug=full</option> option. You need to give |
| 6134 | explicitly <option>--with-debug=detect</option> option instead. | 6134 | explicitly <option>--with-debug=detect</option> option instead. |
diff --git a/include/asm-mips/mach-au1x00/au1xxx_psc.h b/include/asm-mips/mach-au1x00/au1xxx_psc.h index dae4eca2417e..892b7f168eb4 100644 --- a/include/asm-mips/mach-au1x00/au1xxx_psc.h +++ b/include/asm-mips/mach-au1x00/au1xxx_psc.h | |||
| @@ -204,6 +204,14 @@ typedef struct psc_i2s { | |||
| 204 | u32 psc_i2sudf; | 204 | u32 psc_i2sudf; |
| 205 | } psc_i2s_t; | 205 | } psc_i2s_t; |
| 206 | 206 | ||
| 207 | #define PSC_I2SCFG_OFFSET 0x08 | ||
| 208 | #define PSC_I2SMASK_OFFSET 0x0C | ||
| 209 | #define PSC_I2SPCR_OFFSET 0x10 | ||
| 210 | #define PSC_I2SSTAT_OFFSET 0x14 | ||
| 211 | #define PSC_I2SEVENT_OFFSET 0x18 | ||
| 212 | #define PSC_I2SRXTX_OFFSET 0x1C | ||
| 213 | #define PSC_I2SUDF_OFFSET 0x20 | ||
| 214 | |||
| 207 | /* I2S Config Register. */ | 215 | /* I2S Config Register. */ |
| 208 | #define PSC_I2SCFG_RT_MASK (3 << 30) | 216 | #define PSC_I2SCFG_RT_MASK (3 << 30) |
| 209 | #define PSC_I2SCFG_RT_FIFO1 (0 << 30) | 217 | #define PSC_I2SCFG_RT_FIFO1 (0 << 30) |
diff --git a/include/sound/ad1843.h b/include/sound/ad1843.h new file mode 100644 index 000000000000..b236a9d1d6e4 --- /dev/null +++ b/include/sound/ad1843.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org> | ||
| 7 | * Copyright 2008 Thomas Bogendoerfer <tsbogend@franken.de> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __SOUND_AD1843_H | ||
| 11 | #define __SOUND_AD1843_H | ||
| 12 | |||
| 13 | struct snd_ad1843 { | ||
| 14 | void *chip; | ||
| 15 | int (*read)(void *chip, int reg); | ||
| 16 | int (*write)(void *chip, int reg, int val); | ||
| 17 | }; | ||
| 18 | |||
| 19 | #define AD1843_GAIN_RECLEV 0 | ||
| 20 | #define AD1843_GAIN_LINE 1 | ||
| 21 | #define AD1843_GAIN_LINE_2 2 | ||
| 22 | #define AD1843_GAIN_MIC 3 | ||
| 23 | #define AD1843_GAIN_PCM_0 4 | ||
| 24 | #define AD1843_GAIN_PCM_1 5 | ||
| 25 | #define AD1843_GAIN_SIZE (AD1843_GAIN_PCM_1+1) | ||
| 26 | |||
| 27 | int ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id); | ||
| 28 | int ad1843_get_gain(struct snd_ad1843 *ad1843, int id); | ||
| 29 | int ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval); | ||
| 30 | int ad1843_get_recsrc(struct snd_ad1843 *ad1843); | ||
| 31 | int ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc); | ||
| 32 | void ad1843_setup_dac(struct snd_ad1843 *ad1843, | ||
| 33 | unsigned int id, | ||
| 34 | unsigned int framerate, | ||
| 35 | snd_pcm_format_t fmt, | ||
| 36 | unsigned int channels); | ||
| 37 | void ad1843_shutdown_dac(struct snd_ad1843 *ad1843, | ||
| 38 | unsigned int id); | ||
| 39 | void ad1843_setup_adc(struct snd_ad1843 *ad1843, | ||
| 40 | unsigned int framerate, | ||
| 41 | snd_pcm_format_t fmt, | ||
| 42 | unsigned int channels); | ||
| 43 | void ad1843_shutdown_adc(struct snd_ad1843 *ad1843); | ||
| 44 | int ad1843_init(struct snd_ad1843 *ad1843); | ||
| 45 | |||
| 46 | #endif /* __SOUND_AD1843_H */ | ||
diff --git a/include/sound/control.h b/include/sound/control.h index 3dc1291f52db..4721b4bba053 100644 --- a/include/sound/control.h +++ b/include/sound/control.h | |||
| @@ -129,9 +129,6 @@ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn); | |||
| 129 | #define snd_ctl_unregister_ioctl_compat(fcn) | 129 | #define snd_ctl_unregister_ioctl_compat(fcn) |
| 130 | #endif | 130 | #endif |
| 131 | 131 | ||
| 132 | int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control); | ||
| 133 | int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, struct snd_ctl_elem_value *control); | ||
| 134 | |||
| 135 | static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) | 132 | static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) |
| 136 | { | 133 | { |
| 137 | return id->numid - kctl->id.numid; | 134 | return id->numid - kctl->id.numid; |
diff --git a/include/sound/core.h b/include/sound/core.h index 695ee53488a3..558b96284bd2 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
| @@ -412,13 +412,13 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) | |||
| 412 | 412 | ||
| 413 | #endif /* CONFIG_SND_DEBUG */ | 413 | #endif /* CONFIG_SND_DEBUG */ |
| 414 | 414 | ||
| 415 | #ifdef CONFIG_SND_DEBUG_DETECT | 415 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 416 | /** | 416 | /** |
| 417 | * snd_printdd - debug printk | 417 | * snd_printdd - debug printk |
| 418 | * @format: format string | 418 | * @format: format string |
| 419 | * | 419 | * |
| 420 | * Works like snd_printk() for debugging purposes. | 420 | * Works like snd_printk() for debugging purposes. |
| 421 | * Ignored when CONFIG_SND_DEBUG_DETECT is not set. | 421 | * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set. |
| 422 | */ | 422 | */ |
| 423 | #define snd_printdd(format, args...) snd_printk(format, ##args) | 423 | #define snd_printdd(format, args...) snd_printk(format, ##args) |
| 424 | #else | 424 | #else |
| @@ -442,7 +442,7 @@ struct snd_pci_quirk { | |||
| 442 | unsigned short subvendor; /* PCI subvendor ID */ | 442 | unsigned short subvendor; /* PCI subvendor ID */ |
| 443 | unsigned short subdevice; /* PCI subdevice ID */ | 443 | unsigned short subdevice; /* PCI subdevice ID */ |
| 444 | int value; /* value */ | 444 | int value; /* value */ |
| 445 | #ifdef CONFIG_SND_DEBUG_DETECT | 445 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 446 | const char *name; /* name of the device (optional) */ | 446 | const char *name; /* name of the device (optional) */ |
| 447 | #endif | 447 | #endif |
| 448 | }; | 448 | }; |
| @@ -450,7 +450,7 @@ struct snd_pci_quirk { | |||
| 450 | #define _SND_PCI_QUIRK_ID(vend,dev) \ | 450 | #define _SND_PCI_QUIRK_ID(vend,dev) \ |
| 451 | .subvendor = (vend), .subdevice = (dev) | 451 | .subvendor = (vend), .subdevice = (dev) |
| 452 | #define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)} | 452 | #define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)} |
| 453 | #ifdef CONFIG_SND_DEBUG_DETECT | 453 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 454 | #define SND_PCI_QUIRK(vend,dev,xname,val) \ | 454 | #define SND_PCI_QUIRK(vend,dev,xname,val) \ |
| 455 | {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)} | 455 | {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)} |
| 456 | #else | 456 | #else |
diff --git a/include/sound/cs4231-regs.h b/include/sound/cs4231-regs.h index e8d1f3e31f9e..92647532c454 100644 --- a/include/sound/cs4231-regs.h +++ b/include/sound/cs4231-regs.h | |||
| @@ -177,4 +177,12 @@ | |||
| 177 | #define CS4236_RIGHT_WAVE 0x1c /* right wavetable serial port volume */ | 177 | #define CS4236_RIGHT_WAVE 0x1c /* right wavetable serial port volume */ |
| 178 | #define CS4236_VERSION 0x9c /* chip version and ID */ | 178 | #define CS4236_VERSION 0x9c /* chip version and ID */ |
| 179 | 179 | ||
| 180 | /* definitions for extended registers - OPTI93X */ | ||
| 181 | #define OPTi931_AUX_LEFT_INPUT 0x10 | ||
| 182 | #define OPTi931_AUX_RIGHT_INPUT 0x11 | ||
| 183 | #define OPTi93X_MIC_LEFT_INPUT 0x14 | ||
| 184 | #define OPTi93X_MIC_RIGHT_INPUT 0x15 | ||
| 185 | #define OPTi93X_OUT_LEFT 0x16 | ||
| 186 | #define OPTi93X_OUT_RIGHT 0x17 | ||
| 187 | |||
| 180 | #endif /* __SOUND_CS4231_REGS_H */ | 188 | #endif /* __SOUND_CS4231_REGS_H */ |
diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h index 66055d702aa3..f0785f9f4ae4 100644 --- a/include/sound/cs4231.h +++ b/include/sound/cs4231.h | |||
| @@ -58,6 +58,7 @@ | |||
| 58 | /* compatible, but clones */ | 58 | /* compatible, but clones */ |
| 59 | #define CS4231_HW_INTERWAVE 0x1000 /* InterWave chip */ | 59 | #define CS4231_HW_INTERWAVE 0x1000 /* InterWave chip */ |
| 60 | #define CS4231_HW_OPL3SA2 0x1101 /* OPL3-SA2 chip, similar to cs4231 */ | 60 | #define CS4231_HW_OPL3SA2 0x1101 /* OPL3-SA2 chip, similar to cs4231 */ |
| 61 | #define CS4231_HW_OPTI93X 0x1102 /* Opti 930/931/933 */ | ||
| 61 | 62 | ||
| 62 | /* defines for codec.hwshare */ | 63 | /* defines for codec.hwshare */ |
| 63 | #define CS4231_HWSHARE_IRQ (1<<0) | 64 | #define CS4231_HWSHARE_IRQ (1<<0) |
| @@ -120,6 +121,8 @@ unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg); | |||
| 120 | void snd_cs4231_mce_up(struct snd_cs4231 *chip); | 121 | void snd_cs4231_mce_up(struct snd_cs4231 *chip); |
| 121 | void snd_cs4231_mce_down(struct snd_cs4231 *chip); | 122 | void snd_cs4231_mce_down(struct snd_cs4231 *chip); |
| 122 | 123 | ||
| 124 | void snd_cs4231_overrange(struct snd_cs4231 *chip); | ||
| 125 | |||
| 123 | irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id); | 126 | irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id); |
| 124 | 127 | ||
| 125 | const char *snd_cs4231_chip_id(struct snd_cs4231 *chip); | 128 | const char *snd_cs4231_chip_id(struct snd_cs4231 *chip); |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 7b7b9b13b4dd..10ee28eac018 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
| @@ -1670,6 +1670,7 @@ struct snd_emu_chip_details { | |||
| 1670 | unsigned char spi_dac; /* SPI interface for DAC */ | 1670 | unsigned char spi_dac; /* SPI interface for DAC */ |
| 1671 | unsigned char i2c_adc; /* I2C interface for ADC */ | 1671 | unsigned char i2c_adc; /* I2C interface for ADC */ |
| 1672 | unsigned char adc_1361t; /* Use Philips 1361T ADC */ | 1672 | unsigned char adc_1361t; /* Use Philips 1361T ADC */ |
| 1673 | unsigned char invert_shared_spdif; /* analog/digital switch inverted */ | ||
| 1673 | const char *driver; | 1674 | const char *driver; |
| 1674 | const char *name; | 1675 | const char *name; |
| 1675 | const char *id; /* for backward compatibility - can be NULL if not needed */ | 1676 | const char *id; /* for backward compatibility - can be NULL if not needed */ |
diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h index f023c1b97f8c..3d9afb6a8c9c 100644 --- a/include/sound/seq_kernel.h +++ b/include/sound/seq_kernel.h | |||
| @@ -105,7 +105,7 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp, | |||
| 105 | int cap, int type, int midi_channels, int midi_voices, char *portname); | 105 | int cap, int type, int midi_channels, int midi_voices, char *portname); |
| 106 | int snd_seq_event_port_detach(int client, int port); | 106 | int snd_seq_event_port_detach(int client, int port); |
| 107 | 107 | ||
| 108 | #ifdef CONFIG_KMOD | 108 | #ifdef CONFIG_MODULES |
| 109 | void snd_seq_autoload_lock(void); | 109 | void snd_seq_autoload_lock(void); |
| 110 | void snd_seq_autoload_unlock(void); | 110 | void snd_seq_autoload_unlock(void); |
| 111 | #else | 111 | #else |
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index a105b01e06d5..3030fdc6981d 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
| @@ -130,6 +130,13 @@ | |||
| 130 | { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ | 130 | { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ |
| 131 | .shift = wshift, .invert = winvert} | 131 | .shift = wshift, .invert = winvert} |
| 132 | 132 | ||
| 133 | /* generic register modifier widget */ | ||
| 134 | #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ | ||
| 135 | { .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \ | ||
| 136 | .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \ | ||
| 137 | .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ | ||
| 138 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} | ||
| 139 | |||
| 133 | /* dapm kcontrol types */ | 140 | /* dapm kcontrol types */ |
| 134 | #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \ | 141 | #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \ |
| 135 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 142 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| @@ -193,6 +200,7 @@ struct snd_soc_dapm_widget; | |||
| 193 | enum snd_soc_dapm_type; | 200 | enum snd_soc_dapm_type; |
| 194 | struct snd_soc_dapm_path; | 201 | struct snd_soc_dapm_path; |
| 195 | struct snd_soc_dapm_pin; | 202 | struct snd_soc_dapm_pin; |
| 203 | struct snd_soc_dapm_route; | ||
| 196 | 204 | ||
| 197 | /* dapm controls */ | 205 | /* dapm controls */ |
| 198 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 206 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
| @@ -205,25 +213,32 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
| 205 | struct snd_ctl_elem_value *ucontrol); | 213 | struct snd_ctl_elem_value *ucontrol); |
| 206 | int snd_soc_dapm_new_control(struct snd_soc_codec *codec, | 214 | int snd_soc_dapm_new_control(struct snd_soc_codec *codec, |
| 207 | const struct snd_soc_dapm_widget *widget); | 215 | const struct snd_soc_dapm_widget *widget); |
| 216 | int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, | ||
| 217 | const struct snd_soc_dapm_widget *widget, | ||
| 218 | int num); | ||
| 208 | 219 | ||
| 209 | /* dapm path setup */ | 220 | /* dapm path setup */ |
| 210 | int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, | 221 | int __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec, |
| 211 | const char *sink_name, const char *control_name, const char *src_name); | 222 | const char *sink_name, const char *control_name, const char *src_name); |
| 212 | int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); | 223 | int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); |
| 213 | void snd_soc_dapm_free(struct snd_soc_device *socdev); | 224 | void snd_soc_dapm_free(struct snd_soc_device *socdev); |
| 225 | int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | ||
| 226 | const struct snd_soc_dapm_route *route, int num); | ||
| 214 | 227 | ||
| 215 | /* dapm events */ | 228 | /* dapm events */ |
| 216 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, | 229 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, |
| 217 | int event); | 230 | int event); |
| 218 | int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event); | 231 | int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, |
| 232 | enum snd_soc_bias_level level); | ||
| 219 | 233 | ||
| 220 | /* dapm sys fs - used by the core */ | 234 | /* dapm sys fs - used by the core */ |
| 221 | int snd_soc_dapm_sys_add(struct device *dev); | 235 | int snd_soc_dapm_sys_add(struct device *dev); |
| 222 | 236 | ||
| 223 | /* dapm audio endpoint control */ | 237 | /* dapm audio pin control and status */ |
| 224 | int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, | 238 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin); |
| 225 | char *pin, int status); | 239 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin); |
| 226 | int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec); | 240 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin); |
| 241 | int snd_soc_dapm_sync(struct snd_soc_codec *codec); | ||
| 227 | 242 | ||
| 228 | /* dapm widget types */ | 243 | /* dapm widget types */ |
| 229 | enum snd_soc_dapm_type { | 244 | enum snd_soc_dapm_type { |
| @@ -245,6 +260,18 @@ enum snd_soc_dapm_type { | |||
| 245 | snd_soc_dapm_post, /* machine specific post widget - exec last */ | 260 | snd_soc_dapm_post, /* machine specific post widget - exec last */ |
| 246 | }; | 261 | }; |
| 247 | 262 | ||
| 263 | /* | ||
| 264 | * DAPM audio route definition. | ||
| 265 | * | ||
| 266 | * Defines an audio route originating at source via control and finishing | ||
| 267 | * at sink. | ||
| 268 | */ | ||
| 269 | struct snd_soc_dapm_route { | ||
| 270 | const char *sink; | ||
| 271 | const char *control; | ||
| 272 | const char *source; | ||
| 273 | }; | ||
| 274 | |||
| 248 | /* dapm audio path between two widgets */ | 275 | /* dapm audio path between two widgets */ |
| 249 | struct snd_soc_dapm_path { | 276 | struct snd_soc_dapm_path { |
| 250 | char *name; | 277 | char *name; |
| @@ -277,6 +304,9 @@ struct snd_soc_dapm_widget { | |||
| 277 | unsigned char shift; /* bits to shift */ | 304 | unsigned char shift; /* bits to shift */ |
| 278 | unsigned int saved_value; /* widget saved value */ | 305 | unsigned int saved_value; /* widget saved value */ |
| 279 | unsigned int value; /* widget current value */ | 306 | unsigned int value; /* widget current value */ |
| 307 | unsigned int mask; /* non-shifted mask */ | ||
| 308 | unsigned int on_val; /* on state value */ | ||
| 309 | unsigned int off_val; /* off state value */ | ||
| 280 | unsigned char power:1; /* block power status */ | 310 | unsigned char power:1; /* block power status */ |
| 281 | unsigned char invert:1; /* invert the power bit */ | 311 | unsigned char invert:1; /* invert the power bit */ |
| 282 | unsigned char active:1; /* active stream on DAC, ADC's */ | 312 | unsigned char active:1; /* active stream on DAC, ADC's */ |
diff --git a/include/sound/soc.h b/include/sound/soc.h index d3c8c033dff8..1890d87c5204 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
| @@ -73,6 +73,15 @@ | |||
| 73 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ | 73 | .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ |
| 74 | .private_value = (reg_left) | ((shift) << 8) | \ | 74 | .private_value = (reg_left) | ((shift) << 8) | \ |
| 75 | ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) } | 75 | ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) } |
| 76 | #define SOC_DOUBLE_S8_TLV(xname, reg, min, max, tlv_array) \ | ||
| 77 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
| 78 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
| 79 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
| 80 | .tlv.p = (tlv_array), \ | ||
| 81 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ | ||
| 82 | .put = snd_soc_put_volsw_s8, \ | ||
| 83 | .private_value = (reg) | (((signed char)max) << 16) | \ | ||
| 84 | (((signed char)min) << 24) } | ||
| 76 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ | 85 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ |
| 77 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 86 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
| 78 | .mask = xmask, .texts = xtexts } | 87 | .mask = xmask, .texts = xtexts } |
| @@ -91,6 +100,15 @@ | |||
| 91 | .info = snd_soc_info_volsw, \ | 100 | .info = snd_soc_info_volsw, \ |
| 92 | .get = xhandler_get, .put = xhandler_put, \ | 101 | .get = xhandler_get, .put = xhandler_put, \ |
| 93 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) } | 102 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) } |
| 103 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmask, xinvert,\ | ||
| 104 | xhandler_get, xhandler_put, tlv_array) \ | ||
| 105 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
| 106 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
| 107 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
| 108 | .tlv.p = (tlv_array), \ | ||
| 109 | .info = snd_soc_info_volsw, \ | ||
| 110 | .get = xhandler_get, .put = xhandler_put, \ | ||
| 111 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) } | ||
| 94 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ | 112 | #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ |
| 95 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 113 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| 96 | .info = snd_soc_info_bool_ext, \ | 114 | .info = snd_soc_info_bool_ext, \ |
| @@ -103,6 +121,24 @@ | |||
| 103 | .private_value = (unsigned long)&xenum } | 121 | .private_value = (unsigned long)&xenum } |
| 104 | 122 | ||
| 105 | /* | 123 | /* |
| 124 | * Bias levels | ||
| 125 | * | ||
| 126 | * @ON: Bias is fully on for audio playback and capture operations. | ||
| 127 | * @PREPARE: Prepare for audio operations. Called before DAPM switching for | ||
| 128 | * stream start and stop operations. | ||
| 129 | * @STANDBY: Low power standby state when no playback/capture operations are | ||
| 130 | * in progress. NOTE: The transition time between STANDBY and ON | ||
| 131 | * should be as fast as possible and no longer than 10ms. | ||
| 132 | * @OFF: Power Off. No restrictions on transition times. | ||
| 133 | */ | ||
| 134 | enum snd_soc_bias_level { | ||
| 135 | SND_SOC_BIAS_ON, | ||
| 136 | SND_SOC_BIAS_PREPARE, | ||
| 137 | SND_SOC_BIAS_STANDBY, | ||
| 138 | SND_SOC_BIAS_OFF, | ||
| 139 | }; | ||
| 140 | |||
| 141 | /* | ||
| 106 | * Digital Audio Interface (DAI) types | 142 | * Digital Audio Interface (DAI) types |
| 107 | */ | 143 | */ |
| 108 | #define SND_SOC_DAI_AC97 0x1 | 144 | #define SND_SOC_DAI_AC97 0x1 |
| @@ -185,8 +221,7 @@ struct snd_soc_pcm_stream; | |||
| 185 | struct snd_soc_ops; | 221 | struct snd_soc_ops; |
| 186 | struct snd_soc_dai_mode; | 222 | struct snd_soc_dai_mode; |
| 187 | struct snd_soc_pcm_runtime; | 223 | struct snd_soc_pcm_runtime; |
| 188 | struct snd_soc_codec_dai; | 224 | struct snd_soc_dai; |
| 189 | struct snd_soc_cpu_dai; | ||
| 190 | struct snd_soc_codec; | 225 | struct snd_soc_codec; |
| 191 | struct snd_soc_machine_config; | 226 | struct snd_soc_machine_config; |
| 192 | struct soc_enum; | 227 | struct soc_enum; |
| @@ -221,6 +256,27 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | |||
| 221 | struct snd_ac97_bus_ops *ops, int num); | 256 | struct snd_ac97_bus_ops *ops, int num); |
| 222 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); | 257 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); |
| 223 | 258 | ||
| 259 | /* Digital Audio Interface clocking API.*/ | ||
| 260 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
| 261 | unsigned int freq, int dir); | ||
| 262 | |||
| 263 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, | ||
| 264 | int div_id, int div); | ||
| 265 | |||
| 266 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, | ||
| 267 | int pll_id, unsigned int freq_in, unsigned int freq_out); | ||
| 268 | |||
| 269 | /* Digital Audio interface formatting */ | ||
| 270 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); | ||
| 271 | |||
| 272 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | ||
| 273 | unsigned int mask, int slots); | ||
| 274 | |||
| 275 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); | ||
| 276 | |||
| 277 | /* Digital Audio Interface mute */ | ||
| 278 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); | ||
| 279 | |||
| 224 | /* | 280 | /* |
| 225 | *Controls | 281 | *Controls |
| 226 | */ | 282 | */ |
| @@ -249,6 +305,12 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | |||
| 249 | struct snd_ctl_elem_value *ucontrol); | 305 | struct snd_ctl_elem_value *ucontrol); |
| 250 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | 306 | int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, |
| 251 | struct snd_ctl_elem_value *ucontrol); | 307 | struct snd_ctl_elem_value *ucontrol); |
| 308 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | ||
| 309 | struct snd_ctl_elem_info *uinfo); | ||
| 310 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | ||
| 311 | struct snd_ctl_elem_value *ucontrol); | ||
| 312 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | ||
| 313 | struct snd_ctl_elem_value *ucontrol); | ||
| 252 | 314 | ||
| 253 | /* SoC PCM stream information */ | 315 | /* SoC PCM stream information */ |
| 254 | struct snd_soc_pcm_stream { | 316 | struct snd_soc_pcm_stream { |
| @@ -272,87 +334,45 @@ struct snd_soc_ops { | |||
| 272 | int (*trigger)(struct snd_pcm_substream *, int); | 334 | int (*trigger)(struct snd_pcm_substream *, int); |
| 273 | }; | 335 | }; |
| 274 | 336 | ||
| 275 | /* ASoC codec DAI ops */ | 337 | /* ASoC DAI ops */ |
| 276 | struct snd_soc_codec_ops { | 338 | struct snd_soc_dai_ops { |
| 277 | /* codec DAI clocking configuration */ | 339 | /* DAI clocking configuration */ |
| 278 | int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai, | 340 | int (*set_sysclk)(struct snd_soc_dai *dai, |
| 279 | int clk_id, unsigned int freq, int dir); | 341 | int clk_id, unsigned int freq, int dir); |
| 280 | int (*set_pll)(struct snd_soc_codec_dai *codec_dai, | 342 | int (*set_pll)(struct snd_soc_dai *dai, |
| 281 | int pll_id, unsigned int freq_in, unsigned int freq_out); | 343 | int pll_id, unsigned int freq_in, unsigned int freq_out); |
| 282 | int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai, | 344 | int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); |
| 283 | int div_id, int div); | ||
| 284 | 345 | ||
| 285 | /* CPU DAI format configuration */ | 346 | /* DAI format configuration */ |
| 286 | int (*set_fmt)(struct snd_soc_codec_dai *codec_dai, | 347 | int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); |
| 287 | unsigned int fmt); | 348 | int (*set_tdm_slot)(struct snd_soc_dai *dai, |
| 288 | int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai, | ||
| 289 | unsigned int mask, int slots); | 349 | unsigned int mask, int slots); |
| 290 | int (*set_tristate)(struct snd_soc_codec_dai *, int tristate); | 350 | int (*set_tristate)(struct snd_soc_dai *dai, int tristate); |
| 291 | 351 | ||
| 292 | /* digital mute */ | 352 | /* digital mute */ |
| 293 | int (*digital_mute)(struct snd_soc_codec_dai *, int mute); | 353 | int (*digital_mute)(struct snd_soc_dai *dai, int mute); |
| 294 | }; | ||
| 295 | |||
| 296 | /* ASoC cpu DAI ops */ | ||
| 297 | struct snd_soc_cpu_ops { | ||
| 298 | /* CPU DAI clocking configuration */ | ||
| 299 | int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai, | ||
| 300 | int clk_id, unsigned int freq, int dir); | ||
| 301 | int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai, | ||
| 302 | int div_id, int div); | ||
| 303 | int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai, | ||
| 304 | int pll_id, unsigned int freq_in, unsigned int freq_out); | ||
| 305 | |||
| 306 | /* CPU DAI format configuration */ | ||
| 307 | int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai, | ||
| 308 | unsigned int fmt); | ||
| 309 | int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai, | ||
| 310 | unsigned int mask, int slots); | ||
| 311 | int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate); | ||
| 312 | }; | ||
| 313 | |||
| 314 | /* SoC Codec DAI */ | ||
| 315 | struct snd_soc_codec_dai { | ||
| 316 | char *name; | ||
| 317 | int id; | ||
| 318 | unsigned char type; | ||
| 319 | |||
| 320 | /* DAI capabilities */ | ||
| 321 | struct snd_soc_pcm_stream playback; | ||
| 322 | struct snd_soc_pcm_stream capture; | ||
| 323 | |||
| 324 | /* DAI runtime info */ | ||
| 325 | struct snd_soc_codec *codec; | ||
| 326 | unsigned int active; | ||
| 327 | unsigned char pop_wait:1; | ||
| 328 | |||
| 329 | /* ops */ | ||
| 330 | struct snd_soc_ops ops; | ||
| 331 | struct snd_soc_codec_ops dai_ops; | ||
| 332 | |||
| 333 | /* DAI private data */ | ||
| 334 | void *private_data; | ||
| 335 | }; | 354 | }; |
| 336 | 355 | ||
| 337 | /* SoC CPU DAI */ | 356 | /* SoC DAI (Digital Audio Interface) */ |
| 338 | struct snd_soc_cpu_dai { | 357 | struct snd_soc_dai { |
| 339 | |||
| 340 | /* DAI description */ | 358 | /* DAI description */ |
| 341 | char *name; | 359 | char *name; |
| 342 | unsigned int id; | 360 | unsigned int id; |
| 343 | unsigned char type; | 361 | unsigned char type; |
| 344 | 362 | ||
| 345 | /* DAI callbacks */ | 363 | /* DAI callbacks */ |
| 346 | int (*probe)(struct platform_device *pdev); | 364 | int (*probe)(struct platform_device *pdev, |
| 347 | void (*remove)(struct platform_device *pdev); | 365 | struct snd_soc_dai *dai); |
| 366 | void (*remove)(struct platform_device *pdev, | ||
| 367 | struct snd_soc_dai *dai); | ||
| 348 | int (*suspend)(struct platform_device *pdev, | 368 | int (*suspend)(struct platform_device *pdev, |
| 349 | struct snd_soc_cpu_dai *cpu_dai); | 369 | struct snd_soc_dai *dai); |
| 350 | int (*resume)(struct platform_device *pdev, | 370 | int (*resume)(struct platform_device *pdev, |
| 351 | struct snd_soc_cpu_dai *cpu_dai); | 371 | struct snd_soc_dai *dai); |
| 352 | 372 | ||
| 353 | /* ops */ | 373 | /* ops */ |
| 354 | struct snd_soc_ops ops; | 374 | struct snd_soc_ops ops; |
| 355 | struct snd_soc_cpu_ops dai_ops; | 375 | struct snd_soc_dai_ops dai_ops; |
| 356 | 376 | ||
| 357 | /* DAI capabilities */ | 377 | /* DAI capabilities */ |
| 358 | struct snd_soc_pcm_stream capture; | 378 | struct snd_soc_pcm_stream capture; |
| @@ -360,7 +380,9 @@ struct snd_soc_cpu_dai { | |||
| 360 | 380 | ||
| 361 | /* DAI runtime info */ | 381 | /* DAI runtime info */ |
| 362 | struct snd_pcm_runtime *runtime; | 382 | struct snd_pcm_runtime *runtime; |
| 363 | unsigned char active:1; | 383 | struct snd_soc_codec *codec; |
| 384 | unsigned int active; | ||
| 385 | unsigned char pop_wait:1; | ||
| 364 | void *dma_data; | 386 | void *dma_data; |
| 365 | 387 | ||
| 366 | /* DAI private data */ | 388 | /* DAI private data */ |
| @@ -374,7 +396,8 @@ struct snd_soc_codec { | |||
| 374 | struct mutex mutex; | 396 | struct mutex mutex; |
| 375 | 397 | ||
| 376 | /* callbacks */ | 398 | /* callbacks */ |
| 377 | int (*dapm_event)(struct snd_soc_codec *codec, int event); | 399 | int (*set_bias_level)(struct snd_soc_codec *, |
| 400 | enum snd_soc_bias_level level); | ||
| 378 | 401 | ||
| 379 | /* runtime */ | 402 | /* runtime */ |
| 380 | struct snd_card *card; | 403 | struct snd_card *card; |
| @@ -396,12 +419,12 @@ struct snd_soc_codec { | |||
| 396 | /* dapm */ | 419 | /* dapm */ |
| 397 | struct list_head dapm_widgets; | 420 | struct list_head dapm_widgets; |
| 398 | struct list_head dapm_paths; | 421 | struct list_head dapm_paths; |
| 399 | unsigned int dapm_state; | 422 | enum snd_soc_bias_level bias_level; |
| 400 | unsigned int suspend_dapm_state; | 423 | enum snd_soc_bias_level suspend_bias_level; |
| 401 | struct delayed_work delayed_work; | 424 | struct delayed_work delayed_work; |
| 402 | 425 | ||
| 403 | /* codec DAI's */ | 426 | /* codec DAI's */ |
| 404 | struct snd_soc_codec_dai *dai; | 427 | struct snd_soc_dai *dai; |
| 405 | unsigned int num_dai; | 428 | unsigned int num_dai; |
| 406 | }; | 429 | }; |
| 407 | 430 | ||
| @@ -420,12 +443,12 @@ struct snd_soc_platform { | |||
| 420 | int (*probe)(struct platform_device *pdev); | 443 | int (*probe)(struct platform_device *pdev); |
| 421 | int (*remove)(struct platform_device *pdev); | 444 | int (*remove)(struct platform_device *pdev); |
| 422 | int (*suspend)(struct platform_device *pdev, | 445 | int (*suspend)(struct platform_device *pdev, |
| 423 | struct snd_soc_cpu_dai *cpu_dai); | 446 | struct snd_soc_dai *dai); |
| 424 | int (*resume)(struct platform_device *pdev, | 447 | int (*resume)(struct platform_device *pdev, |
| 425 | struct snd_soc_cpu_dai *cpu_dai); | 448 | struct snd_soc_dai *dai); |
| 426 | 449 | ||
| 427 | /* pcm creation and destruction */ | 450 | /* pcm creation and destruction */ |
| 428 | int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, | 451 | int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, |
| 429 | struct snd_pcm *); | 452 | struct snd_pcm *); |
| 430 | void (*pcm_free)(struct snd_pcm *); | 453 | void (*pcm_free)(struct snd_pcm *); |
| 431 | 454 | ||
| @@ -439,8 +462,8 @@ struct snd_soc_dai_link { | |||
| 439 | char *stream_name; /* Stream name */ | 462 | char *stream_name; /* Stream name */ |
| 440 | 463 | ||
| 441 | /* DAI */ | 464 | /* DAI */ |
| 442 | struct snd_soc_codec_dai *codec_dai; | 465 | struct snd_soc_dai *codec_dai; |
| 443 | struct snd_soc_cpu_dai *cpu_dai; | 466 | struct snd_soc_dai *cpu_dai; |
| 444 | 467 | ||
| 445 | /* machine stream operations */ | 468 | /* machine stream operations */ |
| 446 | struct snd_soc_ops *ops; | 469 | struct snd_soc_ops *ops; |
| @@ -467,7 +490,8 @@ struct snd_soc_machine { | |||
| 467 | int (*resume_post)(struct platform_device *pdev); | 490 | int (*resume_post)(struct platform_device *pdev); |
| 468 | 491 | ||
| 469 | /* callbacks */ | 492 | /* callbacks */ |
| 470 | int (*dapm_event)(struct snd_soc_machine *, int event); | 493 | int (*set_bias_level)(struct snd_soc_machine *, |
| 494 | enum snd_soc_bias_level level); | ||
| 471 | 495 | ||
| 472 | /* CPU <--> Codec DAI links */ | 496 | /* CPU <--> Codec DAI links */ |
| 473 | struct snd_soc_dai_link *dai_link; | 497 | struct snd_soc_dai_link *dai_link; |
| @@ -482,6 +506,7 @@ struct snd_soc_device { | |||
| 482 | struct snd_soc_codec *codec; | 506 | struct snd_soc_codec *codec; |
| 483 | struct snd_soc_codec_device *codec_dev; | 507 | struct snd_soc_codec_device *codec_dev; |
| 484 | struct delayed_work delayed_work; | 508 | struct delayed_work delayed_work; |
| 509 | struct work_struct deferred_resume_work; | ||
| 485 | void *codec_data; | 510 | void *codec_data; |
| 486 | }; | 511 | }; |
| 487 | 512 | ||
diff --git a/include/sound/uda1341.h b/include/sound/uda1341.h index 2e564bfb37fe..110d5dc3a2be 100644 --- a/include/sound/uda1341.h +++ b/include/sound/uda1341.h | |||
| @@ -15,8 +15,6 @@ | |||
| 15 | * features support | 15 | * features support |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | /* $Id: uda1341.h,v 1.8 2005/11/17 14:17:21 tiwai Exp $ */ | ||
| 19 | |||
| 20 | #define UDA1341_ALSA_NAME "snd-uda1341" | 18 | #define UDA1341_ALSA_NAME "snd-uda1341" |
| 21 | 19 | ||
| 22 | /* | 20 | /* |
diff --git a/include/sound/version.h b/include/sound/version.h index ed6fb2eb1eac..6b78aff273a8 100644 --- a/include/sound/version.h +++ b/include/sound/version.h | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | /* include/version.h. Generated by alsa/ksync script. */ | 1 | /* include/version.h */ |
| 2 | #define CONFIG_SND_VERSION "1.0.16" | 2 | #define CONFIG_SND_VERSION "1.0.17" |
| 3 | #define CONFIG_SND_DATE "" | 3 | #define CONFIG_SND_DATE "" |
diff --git a/sound/Kconfig b/sound/Kconfig index 4247406160e7..a37bee094eba 100644 --- a/sound/Kconfig +++ b/sound/Kconfig | |||
| @@ -1,11 +1,9 @@ | |||
| 1 | # sound/Config.in | 1 | # sound/Config.in |
| 2 | # | 2 | # |
| 3 | 3 | ||
| 4 | menu "Sound" | 4 | menuconfig SOUND |
| 5 | depends on HAS_IOMEM | ||
| 6 | |||
| 7 | config SOUND | ||
| 8 | tristate "Sound card support" | 5 | tristate "Sound card support" |
| 6 | depends on HAS_IOMEM | ||
| 9 | help | 7 | help |
| 10 | If you have a sound card in your computer, i.e. if it can say more | 8 | If you have a sound card in your computer, i.e. if it can say more |
| 11 | than an occasional beep, say Y. Be sure to have all the information | 9 | than an occasional beep, say Y. Be sure to have all the information |
| @@ -28,22 +26,22 @@ config SOUND | |||
| 28 | and read <file:Documentation/sound/oss/README.modules>; the module | 26 | and read <file:Documentation/sound/oss/README.modules>; the module |
| 29 | will be called soundcore. | 27 | will be called soundcore. |
| 30 | 28 | ||
| 29 | if SOUND | ||
| 30 | |||
| 31 | source "sound/oss/dmasound/Kconfig" | 31 | source "sound/oss/dmasound/Kconfig" |
| 32 | 32 | ||
| 33 | if !M68K | 33 | if !M68K |
| 34 | 34 | ||
| 35 | menu "Advanced Linux Sound Architecture" | 35 | menuconfig SND |
| 36 | depends on SOUND!=n | ||
| 37 | |||
| 38 | config SND | ||
| 39 | tristate "Advanced Linux Sound Architecture" | 36 | tristate "Advanced Linux Sound Architecture" |
| 40 | depends on SOUND | ||
| 41 | help | 37 | help |
| 42 | Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), | 38 | Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), |
| 43 | the new base sound system. | 39 | the new base sound system. |
| 44 | 40 | ||
| 45 | For more information, see <http://www.alsa-project.org/> | 41 | For more information, see <http://www.alsa-project.org/> |
| 46 | 42 | ||
| 43 | if SND | ||
| 44 | |||
| 47 | source "sound/core/Kconfig" | 45 | source "sound/core/Kconfig" |
| 48 | 46 | ||
| 49 | source "sound/drivers/Kconfig" | 47 | source "sound/drivers/Kconfig" |
| @@ -58,9 +56,7 @@ source "sound/aoa/Kconfig" | |||
| 58 | 56 | ||
| 59 | source "sound/arm/Kconfig" | 57 | source "sound/arm/Kconfig" |
| 60 | 58 | ||
| 61 | if SPI | ||
| 62 | source "sound/spi/Kconfig" | 59 | source "sound/spi/Kconfig" |
| 63 | endif | ||
| 64 | 60 | ||
| 65 | source "sound/mips/Kconfig" | 61 | source "sound/mips/Kconfig" |
| 66 | 62 | ||
| @@ -80,22 +76,20 @@ source "sound/parisc/Kconfig" | |||
| 80 | 76 | ||
| 81 | source "sound/soc/Kconfig" | 77 | source "sound/soc/Kconfig" |
| 82 | 78 | ||
| 83 | endmenu | 79 | endif # SND |
| 84 | 80 | ||
| 85 | menu "Open Sound System" | 81 | menuconfig SOUND_PRIME |
| 86 | depends on SOUND!=n | ||
| 87 | |||
| 88 | config SOUND_PRIME | ||
| 89 | tristate "Open Sound System (DEPRECATED)" | 82 | tristate "Open Sound System (DEPRECATED)" |
| 90 | depends on SOUND | ||
| 91 | help | 83 | help |
| 92 | Say 'Y' or 'M' to enable Open Sound System drivers. | 84 | Say 'Y' or 'M' to enable Open Sound System drivers. |
| 93 | 85 | ||
| 86 | if SOUND_PRIME | ||
| 87 | |||
| 94 | source "sound/oss/Kconfig" | 88 | source "sound/oss/Kconfig" |
| 95 | 89 | ||
| 96 | endmenu | 90 | endif # SOUND_PRIME |
| 97 | 91 | ||
| 98 | endif | 92 | endif # !M68K |
| 99 | 93 | ||
| 100 | config AC97_BUS | 94 | config AC97_BUS |
| 101 | tristate | 95 | tristate |
| @@ -105,4 +99,4 @@ config AC97_BUS | |||
| 105 | sound although they're sharing the AC97 bus. Concerned drivers | 99 | sound although they're sharing the AC97 bus. Concerned drivers |
| 106 | should "select" this. | 100 | should "select" this. |
| 107 | 101 | ||
| 108 | endmenu | 102 | endif # SOUND |
diff --git a/sound/aoa/Kconfig b/sound/aoa/Kconfig index 5d5813cec4c8..c081e18b9540 100644 --- a/sound/aoa/Kconfig +++ b/sound/aoa/Kconfig | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | menu "Apple Onboard Audio driver" | 1 | menuconfig SND_AOA |
| 2 | depends on SND!=n && PPC_PMAC | ||
| 3 | |||
| 4 | config SND_AOA | ||
| 5 | tristate "Apple Onboard Audio driver" | 2 | tristate "Apple Onboard Audio driver" |
| 6 | depends on SND | 3 | depends on PPC_PMAC |
| 7 | select SND_PCM | 4 | select SND_PCM |
| 8 | ---help--- | 5 | ---help--- |
| 9 | This option enables the new driver for the various | 6 | This option enables the new driver for the various |
| 10 | Apple Onboard Audio components. | 7 | Apple Onboard Audio components. |
| 11 | 8 | ||
| 9 | if SND_AOA | ||
| 10 | |||
| 12 | source "sound/aoa/fabrics/Kconfig" | 11 | source "sound/aoa/fabrics/Kconfig" |
| 13 | 12 | ||
| 14 | source "sound/aoa/codecs/Kconfig" | 13 | source "sound/aoa/codecs/Kconfig" |
| 15 | 14 | ||
| 16 | source "sound/aoa/soundbus/Kconfig" | 15 | source "sound/aoa/soundbus/Kconfig" |
| 17 | 16 | ||
| 18 | endmenu | 17 | endif # SND_AOA |
diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig index d5fbd6016e93..808eb11ebacd 100644 --- a/sound/aoa/codecs/Kconfig +++ b/sound/aoa/codecs/Kconfig | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | config SND_AOA_ONYX | 1 | config SND_AOA_ONYX |
| 2 | tristate "support Onyx chip" | 2 | tristate "support Onyx chip" |
| 3 | depends on SND_AOA | ||
| 4 | select I2C | 3 | select I2C |
| 5 | select I2C_POWERMAC | 4 | select I2C_POWERMAC |
| 6 | ---help--- | 5 | ---help--- |
| @@ -10,7 +9,6 @@ config SND_AOA_ONYX | |||
| 10 | 9 | ||
| 11 | #config SND_AOA_TOPAZ | 10 | #config SND_AOA_TOPAZ |
| 12 | # tristate "support Topaz chips" | 11 | # tristate "support Topaz chips" |
| 13 | # depends on SND_AOA | ||
| 14 | # ---help--- | 12 | # ---help--- |
| 15 | # This option enables support for the Topaz (CS84xx) | 13 | # This option enables support for the Topaz (CS84xx) |
| 16 | # codec chips found in the latest Apple machines, | 14 | # codec chips found in the latest Apple machines, |
| @@ -19,7 +17,6 @@ config SND_AOA_ONYX | |||
| 19 | 17 | ||
| 20 | config SND_AOA_TAS | 18 | config SND_AOA_TAS |
| 21 | tristate "support TAS chips" | 19 | tristate "support TAS chips" |
| 22 | depends on SND_AOA | ||
| 23 | select I2C | 20 | select I2C |
| 24 | select I2C_POWERMAC | 21 | select I2C_POWERMAC |
| 25 | ---help--- | 22 | ---help--- |
| @@ -29,7 +26,6 @@ config SND_AOA_TAS | |||
| 29 | 26 | ||
| 30 | config SND_AOA_TOONIE | 27 | config SND_AOA_TOONIE |
| 31 | tristate "support Toonie chip" | 28 | tristate "support Toonie chip" |
| 32 | depends on SND_AOA | ||
| 33 | ---help--- | 29 | ---help--- |
| 34 | This option enables support for the toonie codec | 30 | This option enables support for the toonie codec |
| 35 | found in the Mac Mini. If you have a Mac Mini and | 31 | found in the Mac Mini. If you have a Mac Mini and |
diff --git a/sound/aoa/fabrics/Kconfig b/sound/aoa/fabrics/Kconfig index 50d7021ff677..3ca475a886b1 100644 --- a/sound/aoa/fabrics/Kconfig +++ b/sound/aoa/fabrics/Kconfig | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | config SND_AOA_FABRIC_LAYOUT | 1 | config SND_AOA_FABRIC_LAYOUT |
| 2 | tristate "layout-id fabric" | 2 | tristate "layout-id fabric" |
| 3 | depends on SND_AOA | ||
| 4 | select SND_AOA_SOUNDBUS | 3 | select SND_AOA_SOUNDBUS |
| 5 | select SND_AOA_SOUNDBUS_I2S | 4 | select SND_AOA_SOUNDBUS_I2S |
| 6 | ---help--- | 5 | ---help--- |
diff --git a/sound/aoa/soundbus/Kconfig b/sound/aoa/soundbus/Kconfig index 7368b7ddfe0d..839d1137b9b2 100644 --- a/sound/aoa/soundbus/Kconfig +++ b/sound/aoa/soundbus/Kconfig | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | config SND_AOA_SOUNDBUS | 1 | config SND_AOA_SOUNDBUS |
| 2 | tristate "Apple Soundbus support" | 2 | tristate "Apple Soundbus support" |
| 3 | depends on SOUND | ||
| 4 | select SND_PCM | 3 | select SND_PCM |
| 5 | ---help--- | 4 | ---help--- |
| 6 | This option enables the generic driver for the soundbus | 5 | This option enables the generic driver for the soundbus |
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 2e4a5e0d16db..351e19ea3785 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig | |||
| @@ -1,11 +1,19 @@ | |||
| 1 | # ALSA ARM drivers | 1 | # ALSA ARM drivers |
| 2 | 2 | ||
| 3 | menu "ALSA ARM devices" | 3 | menuconfig SND_ARM |
| 4 | depends on SND!=n && ARM | 4 | bool "ARM sound devices" |
| 5 | depends on ARM | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices specific to ARM architectures. | ||
| 9 | Drivers that are implemented on ASoC can be found in | ||
| 10 | "ALSA for SoC audio support" section. | ||
| 11 | |||
| 12 | if SND_ARM | ||
| 5 | 13 | ||
| 6 | config SND_SA11XX_UDA1341 | 14 | config SND_SA11XX_UDA1341 |
| 7 | tristate "SA11xx UDA1341TS driver (iPaq H3600)" | 15 | tristate "SA11xx UDA1341TS driver (iPaq H3600)" |
| 8 | depends on ARCH_SA1100 && SND && L3 | 16 | depends on ARCH_SA1100 && L3 |
| 9 | select SND_PCM | 17 | select SND_PCM |
| 10 | help | 18 | help |
| 11 | Say Y here if you have a Compaq iPaq H3x00 handheld computer | 19 | Say Y here if you have a Compaq iPaq H3x00 handheld computer |
| @@ -16,7 +24,7 @@ config SND_SA11XX_UDA1341 | |||
| 16 | 24 | ||
| 17 | config SND_ARMAACI | 25 | config SND_ARMAACI |
| 18 | tristate "ARM PrimeCell PL041 AC Link support" | 26 | tristate "ARM PrimeCell PL041 AC Link support" |
| 19 | depends on SND && ARM_AMBA | 27 | depends on ARM_AMBA |
| 20 | select SND_PCM | 28 | select SND_PCM |
| 21 | select SND_AC97_CODEC | 29 | select SND_AC97_CODEC |
| 22 | 30 | ||
| @@ -26,11 +34,12 @@ config SND_PXA2XX_PCM | |||
| 26 | 34 | ||
| 27 | config SND_PXA2XX_AC97 | 35 | config SND_PXA2XX_AC97 |
| 28 | tristate "AC97 driver for the Intel PXA2xx chip" | 36 | tristate "AC97 driver for the Intel PXA2xx chip" |
| 29 | depends on ARCH_PXA && SND | 37 | depends on ARCH_PXA |
| 30 | select SND_PXA2XX_PCM | 38 | select SND_PXA2XX_PCM |
| 31 | select SND_AC97_CODEC | 39 | select SND_AC97_CODEC |
| 32 | help | 40 | help |
| 33 | Say Y or M if you want to support any AC97 codec attached to | 41 | Say Y or M if you want to support any AC97 codec attached to |
| 34 | the PXA2xx AC97 interface. | 42 | the PXA2xx AC97 interface. |
| 35 | 43 | ||
| 36 | endmenu | 44 | endif # SND_ARM |
| 45 | |||
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index 0eff33ca0f79..faeddf3ecedb 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c | |||
| @@ -21,8 +21,6 @@ | |||
| 21 | * merged HAL layer (patches from Brian) | 21 | * merged HAL layer (patches from Brian) |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | /* $Id: sa11xx-uda1341.c,v 1.27 2005/12/07 09:13:42 cladisch Exp $ */ | ||
| 25 | |||
| 26 | /*************************************************************************************************** | 24 | /*************************************************************************************************** |
| 27 | * | 25 | * |
| 28 | * To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai | 26 | * To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai |
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index a8d71c6c8e75..335d45ecde6a 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig | |||
| @@ -1,24 +1,19 @@ | |||
| 1 | # ALSA soundcard-configuration | 1 | # ALSA soundcard-configuration |
| 2 | config SND_TIMER | 2 | config SND_TIMER |
| 3 | tristate | 3 | tristate |
| 4 | depends on SND | ||
| 5 | 4 | ||
| 6 | config SND_PCM | 5 | config SND_PCM |
| 7 | tristate | 6 | tristate |
| 8 | select SND_TIMER | 7 | select SND_TIMER |
| 9 | depends on SND | ||
| 10 | 8 | ||
| 11 | config SND_HWDEP | 9 | config SND_HWDEP |
| 12 | tristate | 10 | tristate |
| 13 | depends on SND | ||
| 14 | 11 | ||
| 15 | config SND_RAWMIDI | 12 | config SND_RAWMIDI |
| 16 | tristate | 13 | tristate |
| 17 | depends on SND | ||
| 18 | 14 | ||
| 19 | config SND_SEQUENCER | 15 | config SND_SEQUENCER |
| 20 | tristate "Sequencer support" | 16 | tristate "Sequencer support" |
| 21 | depends on SND | ||
| 22 | select SND_TIMER | 17 | select SND_TIMER |
| 23 | help | 18 | help |
| 24 | Say Y or M to enable MIDI sequencer and router support. This | 19 | Say Y or M to enable MIDI sequencer and router support. This |
| @@ -44,11 +39,9 @@ config SND_SEQ_DUMMY | |||
| 44 | 39 | ||
| 45 | config SND_OSSEMUL | 40 | config SND_OSSEMUL |
| 46 | bool | 41 | bool |
| 47 | depends on SND | ||
| 48 | 42 | ||
| 49 | config SND_MIXER_OSS | 43 | config SND_MIXER_OSS |
| 50 | tristate "OSS Mixer API" | 44 | tristate "OSS Mixer API" |
| 51 | depends on SND | ||
| 52 | select SND_OSSEMUL | 45 | select SND_OSSEMUL |
| 53 | help | 46 | help |
| 54 | To enable OSS mixer API emulation (/dev/mixer*), say Y here | 47 | To enable OSS mixer API emulation (/dev/mixer*), say Y here |
| @@ -61,7 +54,6 @@ config SND_MIXER_OSS | |||
| 61 | 54 | ||
| 62 | config SND_PCM_OSS | 55 | config SND_PCM_OSS |
| 63 | tristate "OSS PCM (digital audio) API" | 56 | tristate "OSS PCM (digital audio) API" |
| 64 | depends on SND | ||
| 65 | select SND_OSSEMUL | 57 | select SND_OSSEMUL |
| 66 | select SND_PCM | 58 | select SND_PCM |
| 67 | help | 59 | help |
| @@ -84,7 +76,7 @@ config SND_PCM_OSS_PLUGINS | |||
| 84 | 76 | ||
| 85 | config SND_SEQUENCER_OSS | 77 | config SND_SEQUENCER_OSS |
| 86 | bool "OSS Sequencer API" | 78 | bool "OSS Sequencer API" |
| 87 | depends on SND && SND_SEQUENCER | 79 | depends on SND_SEQUENCER |
| 88 | select SND_OSSEMUL | 80 | select SND_OSSEMUL |
| 89 | help | 81 | help |
| 90 | Say Y here to enable OSS sequencer emulation (both | 82 | Say Y here to enable OSS sequencer emulation (both |
| @@ -98,7 +90,7 @@ config SND_SEQUENCER_OSS | |||
| 98 | 90 | ||
| 99 | config SND_RTCTIMER | 91 | config SND_RTCTIMER |
| 100 | tristate "RTC Timer support" | 92 | tristate "RTC Timer support" |
| 101 | depends on SND && RTC | 93 | depends on RTC |
| 102 | select SND_TIMER | 94 | select SND_TIMER |
| 103 | help | 95 | help |
| 104 | Say Y here to enable RTC timer support for ALSA. ALSA uses | 96 | Say Y here to enable RTC timer support for ALSA. ALSA uses |
| @@ -123,7 +115,6 @@ config SND_SEQ_RTCTIMER_DEFAULT | |||
| 123 | 115 | ||
| 124 | config SND_DYNAMIC_MINORS | 116 | config SND_DYNAMIC_MINORS |
| 125 | bool "Dynamic device file minor numbers" | 117 | bool "Dynamic device file minor numbers" |
| 126 | depends on SND | ||
| 127 | help | 118 | help |
| 128 | If you say Y here, the minor numbers of ALSA device files in | 119 | If you say Y here, the minor numbers of ALSA device files in |
| 129 | /dev/snd/ are allocated dynamically. This allows you to have | 120 | /dev/snd/ are allocated dynamically. This allows you to have |
| @@ -134,7 +125,6 @@ config SND_DYNAMIC_MINORS | |||
| 134 | 125 | ||
| 135 | config SND_SUPPORT_OLD_API | 126 | config SND_SUPPORT_OLD_API |
| 136 | bool "Support old ALSA API" | 127 | bool "Support old ALSA API" |
| 137 | depends on SND | ||
| 138 | default y | 128 | default y |
| 139 | help | 129 | help |
| 140 | Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3 | 130 | Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3 |
| @@ -142,7 +132,7 @@ config SND_SUPPORT_OLD_API | |||
| 142 | 132 | ||
| 143 | config SND_VERBOSE_PROCFS | 133 | config SND_VERBOSE_PROCFS |
| 144 | bool "Verbose procfs contents" | 134 | bool "Verbose procfs contents" |
| 145 | depends on SND && PROC_FS | 135 | depends on PROC_FS |
| 146 | default y | 136 | default y |
| 147 | help | 137 | help |
| 148 | Say Y here to include code for verbose procfs contents (provides | 138 | Say Y here to include code for verbose procfs contents (provides |
| @@ -151,7 +141,6 @@ config SND_VERBOSE_PROCFS | |||
| 151 | 141 | ||
| 152 | config SND_VERBOSE_PRINTK | 142 | config SND_VERBOSE_PRINTK |
| 153 | bool "Verbose printk" | 143 | bool "Verbose printk" |
| 154 | depends on SND | ||
| 155 | help | 144 | help |
| 156 | Say Y here to enable verbose log messages. These messages | 145 | Say Y here to enable verbose log messages. These messages |
| 157 | will help to identify source file and position containing | 146 | will help to identify source file and position containing |
| @@ -161,16 +150,17 @@ config SND_VERBOSE_PRINTK | |||
| 161 | 150 | ||
| 162 | config SND_DEBUG | 151 | config SND_DEBUG |
| 163 | bool "Debug" | 152 | bool "Debug" |
| 164 | depends on SND | ||
| 165 | help | 153 | help |
| 166 | Say Y here to enable ALSA debug code. | 154 | Say Y here to enable ALSA debug code. |
| 167 | 155 | ||
| 168 | config SND_DEBUG_DETECT | 156 | config SND_DEBUG_VERBOSE |
| 169 | bool "Debug detection" | 157 | bool "More verbose debug" |
| 170 | depends on SND_DEBUG | 158 | depends on SND_DEBUG |
| 171 | help | 159 | help |
| 172 | Say Y here to enable extra-verbose log messages printed when | 160 | Say Y here to enable extra-verbose debugging messages. |
| 173 | detecting devices. | 161 | |
| 162 | Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages. | ||
| 163 | So, say Y only if you are ready to be annoyed. | ||
| 174 | 164 | ||
| 175 | config SND_PCM_XRUN_DEBUG | 165 | config SND_PCM_XRUN_DEBUG |
| 176 | bool "Enable PCM ring buffer overrun/underrun debugging" | 166 | bool "Enable PCM ring buffer overrun/underrun debugging" |
| @@ -184,4 +174,3 @@ config SND_PCM_XRUN_DEBUG | |||
| 184 | 174 | ||
| 185 | config SND_VMASTER | 175 | config SND_VMASTER |
| 186 | bool | 176 | bool |
| 187 | depends on SND | ||
diff --git a/sound/core/control.c b/sound/core/control.c index 01a1a5af47bb..281b2e2ef0ea 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
| @@ -684,7 +684,8 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, | |||
| 684 | return result; | 684 | return result; |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control) | 687 | static int snd_ctl_elem_read(struct snd_card *card, |
| 688 | struct snd_ctl_elem_value *control) | ||
| 688 | { | 689 | { |
| 689 | struct snd_kcontrol *kctl; | 690 | struct snd_kcontrol *kctl; |
| 690 | struct snd_kcontrol_volatile *vd; | 691 | struct snd_kcontrol_volatile *vd; |
| @@ -734,8 +735,8 @@ static int snd_ctl_elem_read_user(struct snd_card *card, | |||
| 734 | return result; | 735 | return result; |
| 735 | } | 736 | } |
| 736 | 737 | ||
| 737 | int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | 738 | static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, |
| 738 | struct snd_ctl_elem_value *control) | 739 | struct snd_ctl_elem_value *control) |
| 739 | { | 740 | { |
| 740 | struct snd_kcontrol *kctl; | 741 | struct snd_kcontrol *kctl; |
| 741 | struct snd_kcontrol_volatile *vd; | 742 | struct snd_kcontrol_volatile *vd; |
diff --git a/sound/core/init.c b/sound/core/init.c index ac0573416130..5c254d498ae0 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
| @@ -46,17 +46,24 @@ static char *slots[SNDRV_CARDS]; | |||
| 46 | module_param_array(slots, charp, NULL, 0444); | 46 | module_param_array(slots, charp, NULL, 0444); |
| 47 | MODULE_PARM_DESC(slots, "Module names assigned to the slots."); | 47 | MODULE_PARM_DESC(slots, "Module names assigned to the slots."); |
| 48 | 48 | ||
| 49 | /* return non-zero if the given index is already reserved for another | 49 | /* return non-zero if the given index is reserved for the given |
| 50 | * module via slots option | 50 | * module via slots option |
| 51 | */ | 51 | */ |
| 52 | static int module_slot_mismatch(struct module *module, int idx) | 52 | static int module_slot_match(struct module *module, int idx) |
| 53 | { | 53 | { |
| 54 | int match = 1; | ||
| 54 | #ifdef MODULE | 55 | #ifdef MODULE |
| 55 | char *s1, *s2; | 56 | const char *s1, *s2; |
| 57 | |||
| 56 | if (!module || !module->name || !slots[idx]) | 58 | if (!module || !module->name || !slots[idx]) |
| 57 | return 0; | 59 | return 0; |
| 58 | s1 = slots[idx]; | 60 | |
| 59 | s2 = module->name; | 61 | s1 = module->name; |
| 62 | s2 = slots[idx]; | ||
| 63 | if (*s2 == '!') { | ||
| 64 | match = 0; /* negative match */ | ||
| 65 | s2++; | ||
| 66 | } | ||
| 60 | /* compare module name strings | 67 | /* compare module name strings |
| 61 | * hyphens are handled as equivalent with underscore | 68 | * hyphens are handled as equivalent with underscore |
| 62 | */ | 69 | */ |
| @@ -68,12 +75,12 @@ static int module_slot_mismatch(struct module *module, int idx) | |||
| 68 | if (c2 == '-') | 75 | if (c2 == '-') |
| 69 | c2 = '_'; | 76 | c2 = '_'; |
| 70 | if (c1 != c2) | 77 | if (c1 != c2) |
| 71 | return 1; | 78 | return !match; |
| 72 | if (!c1) | 79 | if (!c1) |
| 73 | break; | 80 | break; |
| 74 | } | 81 | } |
| 75 | #endif | 82 | #endif /* MODULE */ |
| 76 | return 0; | 83 | return match; |
| 77 | } | 84 | } |
| 78 | 85 | ||
| 79 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 86 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
| @@ -129,7 +136,7 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
| 129 | struct module *module, int extra_size) | 136 | struct module *module, int extra_size) |
| 130 | { | 137 | { |
| 131 | struct snd_card *card; | 138 | struct snd_card *card; |
| 132 | int err; | 139 | int err, idx2; |
| 133 | 140 | ||
| 134 | if (extra_size < 0) | 141 | if (extra_size < 0) |
| 135 | extra_size = 0; | 142 | extra_size = 0; |
| @@ -144,35 +151,41 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
| 144 | err = 0; | 151 | err = 0; |
| 145 | mutex_lock(&snd_card_mutex); | 152 | mutex_lock(&snd_card_mutex); |
| 146 | if (idx < 0) { | 153 | if (idx < 0) { |
| 147 | int idx2; | ||
| 148 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) | 154 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) |
| 149 | /* idx == -1 == 0xffff means: take any free slot */ | 155 | /* idx == -1 == 0xffff means: take any free slot */ |
| 150 | if (~snd_cards_lock & idx & 1<<idx2) { | 156 | if (~snd_cards_lock & idx & 1<<idx2) { |
| 151 | if (module_slot_mismatch(module, idx2)) | 157 | if (module_slot_match(module, idx2)) { |
| 152 | continue; | 158 | idx = idx2; |
| 153 | idx = idx2; | 159 | break; |
| 154 | if (idx >= snd_ecards_limit) | 160 | } |
| 155 | snd_ecards_limit = idx + 1; | 161 | } |
| 156 | break; | 162 | } |
| 163 | if (idx < 0) { | ||
| 164 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) | ||
| 165 | /* idx == -1 == 0xffff means: take any free slot */ | ||
| 166 | if (~snd_cards_lock & idx & 1<<idx2) { | ||
| 167 | if (!slots[idx2] || !*slots[idx2]) { | ||
| 168 | idx = idx2; | ||
| 169 | break; | ||
| 170 | } | ||
| 157 | } | 171 | } |
| 158 | } else { | ||
| 159 | if (idx < snd_ecards_limit) { | ||
| 160 | if (snd_cards_lock & (1 << idx)) | ||
| 161 | err = -EBUSY; /* invalid */ | ||
| 162 | } else { | ||
| 163 | if (idx < SNDRV_CARDS) | ||
| 164 | snd_ecards_limit = idx + 1; /* increase the limit */ | ||
| 165 | else | ||
| 166 | err = -ENODEV; | ||
| 167 | } | ||
| 168 | } | 172 | } |
| 169 | if (idx < 0 || err < 0) { | 173 | if (idx < 0) |
| 174 | err = -ENODEV; | ||
| 175 | else if (idx < snd_ecards_limit) { | ||
| 176 | if (snd_cards_lock & (1 << idx)) | ||
| 177 | err = -EBUSY; /* invalid */ | ||
| 178 | } else if (idx >= SNDRV_CARDS) | ||
| 179 | err = -ENODEV; | ||
| 180 | if (err < 0) { | ||
| 170 | mutex_unlock(&snd_card_mutex); | 181 | mutex_unlock(&snd_card_mutex); |
| 171 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", | 182 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", |
| 172 | idx, snd_ecards_limit - 1, err); | 183 | idx, snd_ecards_limit - 1, err); |
| 173 | goto __error; | 184 | goto __error; |
| 174 | } | 185 | } |
| 175 | snd_cards_lock |= 1 << idx; /* lock it */ | 186 | snd_cards_lock |= 1 << idx; /* lock it */ |
| 187 | if (idx >= snd_ecards_limit) | ||
| 188 | snd_ecards_limit = idx + 1; /* increase the limit */ | ||
| 176 | mutex_unlock(&snd_card_mutex); | 189 | mutex_unlock(&snd_card_mutex); |
| 177 | card->number = idx; | 190 | card->number = idx; |
| 178 | card->module = module; | 191 | card->module = module; |
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 23b7bc02728b..f5d6d8d12979 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c | |||
| @@ -80,68 +80,6 @@ struct snd_mem_list { | |||
| 80 | #endif | 80 | #endif |
| 81 | 81 | ||
| 82 | /* | 82 | /* |
| 83 | * Hacks | ||
| 84 | */ | ||
| 85 | |||
| 86 | #if defined(__i386__) | ||
| 87 | /* | ||
| 88 | * A hack to allocate large buffers via dma_alloc_coherent() | ||
| 89 | * | ||
| 90 | * since dma_alloc_coherent always tries GFP_DMA when the requested | ||
| 91 | * pci memory region is below 32bit, it happens quite often that even | ||
| 92 | * 2 order of pages cannot be allocated. | ||
| 93 | * | ||
| 94 | * so in the following, we allocate at first without dma_mask, so that | ||
| 95 | * allocation will be done without GFP_DMA. if the area doesn't match | ||
| 96 | * with the requested region, then realloate with the original dma_mask | ||
| 97 | * again. | ||
| 98 | * | ||
| 99 | * Really, we want to move this type of thing into dma_alloc_coherent() | ||
| 100 | * so dma_mask doesn't have to be messed with. | ||
| 101 | */ | ||
| 102 | |||
| 103 | static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size, | ||
| 104 | dma_addr_t *dma_handle, | ||
| 105 | gfp_t flags) | ||
| 106 | { | ||
| 107 | void *ret; | ||
| 108 | u64 dma_mask, coherent_dma_mask; | ||
| 109 | |||
| 110 | if (dev == NULL || !dev->dma_mask) | ||
| 111 | return dma_alloc_coherent(dev, size, dma_handle, flags); | ||
| 112 | dma_mask = *dev->dma_mask; | ||
| 113 | coherent_dma_mask = dev->coherent_dma_mask; | ||
| 114 | *dev->dma_mask = 0xffffffff; /* do without masking */ | ||
| 115 | dev->coherent_dma_mask = 0xffffffff; /* do without masking */ | ||
| 116 | ret = dma_alloc_coherent(dev, size, dma_handle, flags); | ||
| 117 | *dev->dma_mask = dma_mask; /* restore */ | ||
| 118 | dev->coherent_dma_mask = coherent_dma_mask; /* restore */ | ||
| 119 | if (ret) { | ||
| 120 | /* obtained address is out of range? */ | ||
| 121 | if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) { | ||
| 122 | /* reallocate with the proper mask */ | ||
| 123 | dma_free_coherent(dev, size, ret, *dma_handle); | ||
| 124 | ret = dma_alloc_coherent(dev, size, dma_handle, flags); | ||
| 125 | } | ||
| 126 | } else { | ||
| 127 | /* wish to success now with the proper mask... */ | ||
| 128 | if (dma_mask != 0xffffffffUL) { | ||
| 129 | /* allocation with GFP_ATOMIC to avoid the long stall */ | ||
| 130 | flags &= ~GFP_KERNEL; | ||
| 131 | flags |= GFP_ATOMIC; | ||
| 132 | ret = dma_alloc_coherent(dev, size, dma_handle, flags); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | return ret; | ||
| 136 | } | ||
| 137 | |||
| 138 | /* redefine dma_alloc_coherent for some architectures */ | ||
| 139 | #undef dma_alloc_coherent | ||
| 140 | #define dma_alloc_coherent snd_dma_hack_alloc_coherent | ||
| 141 | |||
| 142 | #endif /* arch */ | ||
| 143 | |||
| 144 | /* | ||
| 145 | * | 83 | * |
| 146 | * Generic memory allocators | 84 | * Generic memory allocators |
| 147 | * | 85 | * |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 47cfa5186e34..7a1545d2d953 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
| @@ -148,7 +148,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) | |||
| 148 | return NULL; | 148 | return NULL; |
| 149 | } | 149 | } |
| 150 | spin_unlock_irqrestore(&clients_lock, flags); | 150 | spin_unlock_irqrestore(&clients_lock, flags); |
| 151 | #ifdef CONFIG_KMOD | 151 | #ifdef CONFIG_MODULES |
| 152 | if (!in_interrupt()) { | 152 | if (!in_interrupt()) { |
| 153 | static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; | 153 | static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; |
| 154 | static char card_requested[SNDRV_CARDS]; | 154 | static char card_requested[SNDRV_CARDS]; |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 2f00ad28a2b7..05410e536a4f 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
| @@ -124,7 +124,7 @@ static void snd_seq_device_info(struct snd_info_entry *entry, | |||
| 124 | * load all registered drivers (called from seq_clientmgr.c) | 124 | * load all registered drivers (called from seq_clientmgr.c) |
| 125 | */ | 125 | */ |
| 126 | 126 | ||
| 127 | #ifdef CONFIG_KMOD | 127 | #ifdef CONFIG_MODULES |
| 128 | /* avoid auto-loading during module_init() */ | 128 | /* avoid auto-loading during module_init() */ |
| 129 | static int snd_seq_in_init; | 129 | static int snd_seq_in_init; |
| 130 | void snd_seq_autoload_lock(void) | 130 | void snd_seq_autoload_lock(void) |
| @@ -140,7 +140,7 @@ void snd_seq_autoload_unlock(void) | |||
| 140 | 140 | ||
| 141 | void snd_seq_device_load_drivers(void) | 141 | void snd_seq_device_load_drivers(void) |
| 142 | { | 142 | { |
| 143 | #ifdef CONFIG_KMOD | 143 | #ifdef CONFIG_MODULES |
| 144 | struct ops_list *ops; | 144 | struct ops_list *ops; |
| 145 | 145 | ||
| 146 | /* Calling request_module during module_init() | 146 | /* Calling request_module during module_init() |
| @@ -566,7 +566,5 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers); | |||
| 566 | EXPORT_SYMBOL(snd_seq_device_new); | 566 | EXPORT_SYMBOL(snd_seq_device_new); |
| 567 | EXPORT_SYMBOL(snd_seq_device_register_driver); | 567 | EXPORT_SYMBOL(snd_seq_device_register_driver); |
| 568 | EXPORT_SYMBOL(snd_seq_device_unregister_driver); | 568 | EXPORT_SYMBOL(snd_seq_device_unregister_driver); |
| 569 | #ifdef CONFIG_KMOD | ||
| 570 | EXPORT_SYMBOL(snd_seq_autoload_lock); | 569 | EXPORT_SYMBOL(snd_seq_autoload_lock); |
| 571 | EXPORT_SYMBOL(snd_seq_autoload_unlock); | 570 | EXPORT_SYMBOL(snd_seq_autoload_unlock); |
| 572 | #endif | ||
diff --git a/sound/core/sound.c b/sound/core/sound.c index 6c8ab48c689a..09a94953745a 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
| @@ -60,14 +60,14 @@ EXPORT_SYMBOL(snd_ecards_limit); | |||
| 60 | static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; | 60 | static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; |
| 61 | static DEFINE_MUTEX(sound_mutex); | 61 | static DEFINE_MUTEX(sound_mutex); |
| 62 | 62 | ||
| 63 | #ifdef CONFIG_KMOD | 63 | #ifdef CONFIG_MODULES |
| 64 | 64 | ||
| 65 | /** | 65 | /** |
| 66 | * snd_request_card - try to load the card module | 66 | * snd_request_card - try to load the card module |
| 67 | * @card: the card number | 67 | * @card: the card number |
| 68 | * | 68 | * |
| 69 | * Tries to load the module "snd-card-X" for the given card number | 69 | * Tries to load the module "snd-card-X" for the given card number |
| 70 | * via KMOD. Returns immediately if already loaded. | 70 | * via request_module. Returns immediately if already loaded. |
| 71 | */ | 71 | */ |
| 72 | void snd_request_card(int card) | 72 | void snd_request_card(int card) |
| 73 | { | 73 | { |
| @@ -92,7 +92,7 @@ static void snd_request_other(int minor) | |||
| 92 | request_module(str); | 92 | request_module(str); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | #endif /* request_module support */ | 95 | #endif /* modular kernel */ |
| 96 | 96 | ||
| 97 | /** | 97 | /** |
| 98 | * snd_lookup_minor_data - get user data of a registered device | 98 | * snd_lookup_minor_data - get user data of a registered device |
| @@ -132,7 +132,7 @@ static int snd_open(struct inode *inode, struct file *file) | |||
| 132 | return -ENODEV; | 132 | return -ENODEV; |
| 133 | mptr = snd_minors[minor]; | 133 | mptr = snd_minors[minor]; |
| 134 | if (mptr == NULL) { | 134 | if (mptr == NULL) { |
| 135 | #ifdef CONFIG_KMOD | 135 | #ifdef CONFIG_MODULES |
| 136 | int dev = SNDRV_MINOR_DEVICE(minor); | 136 | int dev = SNDRV_MINOR_DEVICE(minor); |
| 137 | if (dev == SNDRV_MINOR_CONTROL) { | 137 | if (dev == SNDRV_MINOR_CONTROL) { |
| 138 | /* /dev/aloadC? */ | 138 | /* /dev/aloadC? */ |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 9d8184a2c2d0..0af337efc64e 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
| @@ -146,7 +146,7 @@ static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) | |||
| 146 | return NULL; | 146 | return NULL; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | #ifdef CONFIG_KMOD | 149 | #ifdef CONFIG_MODULES |
| 150 | 150 | ||
| 151 | static void snd_timer_request(struct snd_timer_id *tid) | 151 | static void snd_timer_request(struct snd_timer_id *tid) |
| 152 | { | 152 | { |
| @@ -259,8 +259,8 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
| 259 | /* open a master instance */ | 259 | /* open a master instance */ |
| 260 | mutex_lock(®ister_mutex); | 260 | mutex_lock(®ister_mutex); |
| 261 | timer = snd_timer_find(tid); | 261 | timer = snd_timer_find(tid); |
| 262 | #ifdef CONFIG_KMOD | 262 | #ifdef CONFIG_MODULES |
| 263 | if (timer == NULL) { | 263 | if (!timer) { |
| 264 | mutex_unlock(®ister_mutex); | 264 | mutex_unlock(®ister_mutex); |
| 265 | snd_timer_request(tid); | 265 | snd_timer_request(tid); |
| 266 | mutex_lock(®ister_mutex); | 266 | mutex_lock(®ister_mutex); |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 602b58e3b55d..255fd18b9aec 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
| @@ -1,15 +1,41 @@ | |||
| 1 | # ALSA generic drivers | 1 | config SND_MPU401_UART |
| 2 | tristate | ||
| 3 | select SND_RAWMIDI | ||
| 2 | 4 | ||
| 3 | menu "Generic devices" | 5 | config SND_OPL3_LIB |
| 4 | depends on SND!=n | 6 | tristate |
| 7 | select SND_TIMER | ||
| 8 | select SND_HWDEP | ||
| 5 | 9 | ||
| 10 | config SND_OPL4_LIB | ||
| 11 | tristate | ||
| 12 | select SND_TIMER | ||
| 13 | select SND_HWDEP | ||
| 14 | |||
| 15 | config SND_VX_LIB | ||
| 16 | tristate | ||
| 17 | select SND_HWDEP | ||
| 18 | select SND_PCM | ||
| 19 | |||
| 20 | config SND_AC97_CODEC | ||
| 21 | tristate | ||
| 22 | select SND_PCM | ||
| 23 | select AC97_BUS | ||
| 24 | select SND_VMASTER | ||
| 25 | |||
| 26 | menuconfig SND_DRIVERS | ||
| 27 | bool "Generic sound devices" | ||
| 28 | default y | ||
| 29 | help | ||
| 30 | Support for generic sound devices. | ||
| 31 | |||
| 32 | if SND_DRIVERS | ||
| 6 | 33 | ||
| 7 | config SND_PCSP | 34 | config SND_PCSP |
| 8 | tristate "PC-Speaker support (READ HELP!)" | 35 | tristate "PC-Speaker support (READ HELP!)" |
| 9 | depends on PCSPKR_PLATFORM && X86_PC && HIGH_RES_TIMERS | 36 | depends on PCSPKR_PLATFORM && X86_PC && HIGH_RES_TIMERS |
| 10 | depends on INPUT | 37 | depends on INPUT |
| 11 | depends on EXPERIMENTAL | 38 | depends on EXPERIMENTAL |
| 12 | depends on SND | ||
| 13 | select SND_PCM | 39 | select SND_PCM |
| 14 | help | 40 | help |
| 15 | If you don't have a sound card in your computer, you can include a | 41 | If you don't have a sound card in your computer, you can include a |
| @@ -35,33 +61,8 @@ config SND_PCSP | |||
| 35 | Say M if you don't. | 61 | Say M if you don't. |
| 36 | Say Y only if you really know what you do. | 62 | Say Y only if you really know what you do. |
| 37 | 63 | ||
| 38 | config SND_MPU401_UART | ||
| 39 | tristate | ||
| 40 | select SND_RAWMIDI | ||
| 41 | |||
| 42 | config SND_OPL3_LIB | ||
| 43 | tristate | ||
| 44 | select SND_TIMER | ||
| 45 | select SND_HWDEP | ||
| 46 | |||
| 47 | config SND_OPL4_LIB | ||
| 48 | tristate | ||
| 49 | select SND_TIMER | ||
| 50 | select SND_HWDEP | ||
| 51 | |||
| 52 | config SND_VX_LIB | ||
| 53 | tristate | ||
| 54 | select SND_HWDEP | ||
| 55 | select SND_PCM | ||
| 56 | |||
| 57 | config SND_AC97_CODEC | ||
| 58 | tristate | ||
| 59 | select SND_PCM | ||
| 60 | select AC97_BUS | ||
| 61 | |||
| 62 | config SND_DUMMY | 64 | config SND_DUMMY |
| 63 | tristate "Dummy (/dev/null) soundcard" | 65 | tristate "Dummy (/dev/null) soundcard" |
| 64 | depends on SND | ||
| 65 | select SND_PCM | 66 | select SND_PCM |
| 66 | help | 67 | help |
| 67 | Say Y here to include the dummy driver. This driver does | 68 | Say Y here to include the dummy driver. This driver does |
| @@ -90,7 +91,6 @@ config SND_VIRMIDI | |||
| 90 | 91 | ||
| 91 | config SND_MTPAV | 92 | config SND_MTPAV |
| 92 | tristate "MOTU MidiTimePiece AV multiport MIDI" | 93 | tristate "MOTU MidiTimePiece AV multiport MIDI" |
| 93 | depends on SND | ||
| 94 | select SND_RAWMIDI | 94 | select SND_RAWMIDI |
| 95 | help | 95 | help |
| 96 | To use a MOTU MidiTimePiece AV multiport MIDI adapter | 96 | To use a MOTU MidiTimePiece AV multiport MIDI adapter |
| @@ -102,7 +102,7 @@ config SND_MTPAV | |||
| 102 | 102 | ||
| 103 | config SND_MTS64 | 103 | config SND_MTS64 |
| 104 | tristate "ESI Miditerminal 4140 driver" | 104 | tristate "ESI Miditerminal 4140 driver" |
| 105 | depends on SND && PARPORT | 105 | depends on PARPORT |
| 106 | select SND_RAWMIDI | 106 | select SND_RAWMIDI |
| 107 | help | 107 | help |
| 108 | The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with | 108 | The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with |
| @@ -115,7 +115,6 @@ config SND_MTS64 | |||
| 115 | 115 | ||
| 116 | config SND_SERIAL_U16550 | 116 | config SND_SERIAL_U16550 |
| 117 | tristate "UART16550 serial MIDI driver" | 117 | tristate "UART16550 serial MIDI driver" |
| 118 | depends on SND | ||
| 119 | select SND_RAWMIDI | 118 | select SND_RAWMIDI |
| 120 | help | 119 | help |
| 121 | To include support for MIDI serial port interfaces, say Y here | 120 | To include support for MIDI serial port interfaces, say Y here |
| @@ -131,7 +130,6 @@ config SND_SERIAL_U16550 | |||
| 131 | 130 | ||
| 132 | config SND_MPU401 | 131 | config SND_MPU401 |
| 133 | tristate "Generic MPU-401 UART driver" | 132 | tristate "Generic MPU-401 UART driver" |
| 134 | depends on SND | ||
| 135 | select SND_MPU401_UART | 133 | select SND_MPU401_UART |
| 136 | help | 134 | help |
| 137 | Say Y here to include support for MIDI ports compatible with | 135 | Say Y here to include support for MIDI ports compatible with |
| @@ -142,7 +140,7 @@ config SND_MPU401 | |||
| 142 | 140 | ||
| 143 | config SND_PORTMAN2X4 | 141 | config SND_PORTMAN2X4 |
| 144 | tristate "Portman 2x4 driver" | 142 | tristate "Portman 2x4 driver" |
| 145 | depends on SND && PARPORT | 143 | depends on PARPORT |
| 146 | select SND_RAWMIDI | 144 | select SND_RAWMIDI |
| 147 | help | 145 | help |
| 148 | Say Y here to include support for Midiman Portman 2x4 parallel | 146 | Say Y here to include support for Midiman Portman 2x4 parallel |
| @@ -153,7 +151,7 @@ config SND_PORTMAN2X4 | |||
| 153 | 151 | ||
| 154 | config SND_ML403_AC97CR | 152 | config SND_ML403_AC97CR |
| 155 | tristate "Xilinx ML403 AC97 Controller Reference" | 153 | tristate "Xilinx ML403 AC97 Controller Reference" |
| 156 | depends on SND && XILINX_VIRTEX | 154 | depends on XILINX_VIRTEX |
| 157 | select SND_AC97_CODEC | 155 | select SND_AC97_CODEC |
| 158 | help | 156 | help |
| 159 | Say Y here to include support for the | 157 | Say Y here to include support for the |
| @@ -163,4 +161,25 @@ config SND_ML403_AC97CR | |||
| 163 | To compile this driver as a module, choose M here: the module | 161 | To compile this driver as a module, choose M here: the module |
| 164 | will be called snd-ml403_ac97cr. | 162 | will be called snd-ml403_ac97cr. |
| 165 | 163 | ||
| 166 | endmenu | 164 | config SND_AC97_POWER_SAVE |
| 165 | bool "AC97 Power-Saving Mode" | ||
| 166 | depends on SND_AC97_CODEC && EXPERIMENTAL | ||
| 167 | default n | ||
| 168 | help | ||
| 169 | Say Y here to enable the aggressive power-saving support of | ||
| 170 | AC97 codecs. In this mode, the power-mode is dynamically | ||
| 171 | controlled at each open/close. | ||
| 172 | |||
| 173 | The mode is activated by passing power_save=1 option to | ||
| 174 | snd-ac97-codec driver. You can toggle it dynamically over | ||
| 175 | sysfs, too. | ||
| 176 | |||
| 177 | config SND_AC97_POWER_SAVE_DEFAULT | ||
| 178 | int "Default time-out for AC97 power-save mode" | ||
| 179 | depends on SND_AC97_POWER_SAVE | ||
| 180 | default 0 | ||
| 181 | help | ||
| 182 | The default time-out value in seconds for AC97 automatic | ||
| 183 | power-save mode. 0 means to disable the power-save mode. | ||
| 184 | |||
| 185 | endif # SND_DRIVERS | ||
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index 1dfe6948e6ff..efd22e92bced 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c | |||
| @@ -183,7 +183,7 @@ static int vx_hwdep_dsp_load(struct snd_hwdep *hw, | |||
| 183 | kfree(fw); | 183 | kfree(fw); |
| 184 | return -ENOMEM; | 184 | return -ENOMEM; |
| 185 | } | 185 | } |
| 186 | if (copy_from_user(fw->data, dsp->image, dsp->length)) { | 186 | if (copy_from_user((void *)fw->data, dsp->image, dsp->length)) { |
| 187 | free_fw(fw); | 187 | free_fw(fw); |
| 188 | return -EFAULT; | 188 | return -EFAULT; |
| 189 | } | 189 | } |
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index e57e9cbe6a0f..9c3d361accfb 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <asm/unaligned.h> | ||
| 26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
| 27 | #include <sound/control.h> | 28 | #include <sound/control.h> |
| 28 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
| @@ -264,10 +265,7 @@ int snd_cs8427_create(struct snd_i2c_bus *bus, | |||
| 264 | goto __fail; | 265 | goto __fail; |
| 265 | } | 266 | } |
| 266 | /* write default channel status bytes */ | 267 | /* write default channel status bytes */ |
| 267 | buf[0] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 0)); | 268 | put_unaligned_le32(SNDRV_PCM_DEFAULT_CON_SPDIF, buf); |
| 268 | buf[1] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 8)); | ||
| 269 | buf[2] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 16)); | ||
| 270 | buf[3] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 24)); | ||
| 271 | memset(buf + 4, 0, 24 - 4); | 269 | memset(buf + 4, 0, 24 - 4); |
| 272 | if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0) | 270 | if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0) |
| 273 | goto __fail; | 271 | goto __fail; |
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c index bfa5d2c3608b..1f4942ea1414 100644 --- a/sound/i2c/l3/uda1341.c +++ b/sound/i2c/l3/uda1341.c | |||
| @@ -17,8 +17,6 @@ | |||
| 17 | * 2002-05-12 Tomas Kasparek another code cleanup | 17 | * 2002-05-12 Tomas Kasparek another code cleanup |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | /* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */ | ||
| 21 | |||
| 22 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 23 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 24 | #include <linux/types.h> | 22 | #include <linux/types.h> |
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 2639a6ab8f2e..25347a25d63c 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
| @@ -21,12 +21,17 @@ config SND_SB16_DSP | |||
| 21 | select SND_PCM | 21 | select SND_PCM |
| 22 | select SND_SB_COMMON | 22 | select SND_SB_COMMON |
| 23 | 23 | ||
| 24 | menu "ISA devices" | 24 | menuconfig SND_ISA |
| 25 | depends on SND!=n && ISA && ISA_DMA_API | 25 | bool "ISA sound devices" |
| 26 | depends on ISA && ISA_DMA_API | ||
| 27 | default y | ||
| 28 | help | ||
| 29 | Support for sound devices connected via the ISA bus. | ||
| 30 | |||
| 31 | if SND_ISA | ||
| 26 | 32 | ||
| 27 | config SND_ADLIB | 33 | config SND_ADLIB |
| 28 | tristate "AdLib FM card" | 34 | tristate "AdLib FM card" |
| 29 | depends on SND | ||
| 30 | select SND_OPL3_LIB | 35 | select SND_OPL3_LIB |
| 31 | help | 36 | help |
| 32 | Say Y here to include support for AdLib FM cards. | 37 | Say Y here to include support for AdLib FM cards. |
| @@ -36,7 +41,7 @@ config SND_ADLIB | |||
| 36 | 41 | ||
| 37 | config SND_AD1816A | 42 | config SND_AD1816A |
| 38 | tristate "Analog Devices SoundPort AD1816A" | 43 | tristate "Analog Devices SoundPort AD1816A" |
| 39 | depends on SND && PNP && ISA | 44 | depends on PNP |
| 40 | select ISAPNP | 45 | select ISAPNP |
| 41 | select SND_OPL3_LIB | 46 | select SND_OPL3_LIB |
| 42 | select SND_MPU401_UART | 47 | select SND_MPU401_UART |
| @@ -50,7 +55,6 @@ config SND_AD1816A | |||
| 50 | 55 | ||
| 51 | config SND_AD1848 | 56 | config SND_AD1848 |
| 52 | tristate "Generic AD1848/CS4248 driver" | 57 | tristate "Generic AD1848/CS4248 driver" |
| 53 | depends on SND | ||
| 54 | select SND_AD1848_LIB | 58 | select SND_AD1848_LIB |
| 55 | help | 59 | help |
| 56 | Say Y here to include support for AD1848 (Analog Devices) or | 60 | Say Y here to include support for AD1848 (Analog Devices) or |
| @@ -64,7 +68,7 @@ config SND_AD1848 | |||
| 64 | 68 | ||
| 65 | config SND_ALS100 | 69 | config SND_ALS100 |
| 66 | tristate "Avance Logic ALS100/ALS120" | 70 | tristate "Avance Logic ALS100/ALS120" |
| 67 | depends on SND && PNP && ISA | 71 | depends on PNP |
| 68 | select ISAPNP | 72 | select ISAPNP |
| 69 | select SND_OPL3_LIB | 73 | select SND_OPL3_LIB |
| 70 | select SND_MPU401_UART | 74 | select SND_MPU401_UART |
| @@ -78,7 +82,7 @@ config SND_ALS100 | |||
| 78 | 82 | ||
| 79 | config SND_AZT2320 | 83 | config SND_AZT2320 |
| 80 | tristate "Aztech Systems AZT2320" | 84 | tristate "Aztech Systems AZT2320" |
| 81 | depends on SND && PNP && ISA | 85 | depends on PNP |
| 82 | select ISAPNP | 86 | select ISAPNP |
| 83 | select SND_OPL3_LIB | 87 | select SND_OPL3_LIB |
| 84 | select SND_MPU401_UART | 88 | select SND_MPU401_UART |
| @@ -92,7 +96,6 @@ config SND_AZT2320 | |||
| 92 | 96 | ||
| 93 | config SND_CMI8330 | 97 | config SND_CMI8330 |
| 94 | tristate "C-Media CMI8330" | 98 | tristate "C-Media CMI8330" |
| 95 | depends on SND | ||
| 96 | select SND_AD1848_LIB | 99 | select SND_AD1848_LIB |
| 97 | select SND_SB16_DSP | 100 | select SND_SB16_DSP |
| 98 | help | 101 | help |
| @@ -104,7 +107,6 @@ config SND_CMI8330 | |||
| 104 | 107 | ||
| 105 | config SND_CS4231 | 108 | config SND_CS4231 |
| 106 | tristate "Generic Cirrus Logic CS4231 driver" | 109 | tristate "Generic Cirrus Logic CS4231 driver" |
| 107 | depends on SND | ||
| 108 | select SND_MPU401_UART | 110 | select SND_MPU401_UART |
| 109 | select SND_CS4231_LIB | 111 | select SND_CS4231_LIB |
| 110 | help | 112 | help |
| @@ -116,7 +118,6 @@ config SND_CS4231 | |||
| 116 | 118 | ||
| 117 | config SND_CS4232 | 119 | config SND_CS4232 |
| 118 | tristate "Generic Cirrus Logic CS4232 driver" | 120 | tristate "Generic Cirrus Logic CS4232 driver" |
| 119 | depends on SND | ||
| 120 | select SND_OPL3_LIB | 121 | select SND_OPL3_LIB |
| 121 | select SND_MPU401_UART | 122 | select SND_MPU401_UART |
| 122 | select SND_CS4231_LIB | 123 | select SND_CS4231_LIB |
| @@ -129,7 +130,6 @@ config SND_CS4232 | |||
| 129 | 130 | ||
| 130 | config SND_CS4236 | 131 | config SND_CS4236 |
| 131 | tristate "Generic Cirrus Logic CS4236+ driver" | 132 | tristate "Generic Cirrus Logic CS4236+ driver" |
| 132 | depends on SND | ||
| 133 | select SND_OPL3_LIB | 133 | select SND_OPL3_LIB |
| 134 | select SND_MPU401_UART | 134 | select SND_MPU401_UART |
| 135 | select SND_CS4231_LIB | 135 | select SND_CS4231_LIB |
| @@ -142,7 +142,7 @@ config SND_CS4236 | |||
| 142 | 142 | ||
| 143 | config SND_DT019X | 143 | config SND_DT019X |
| 144 | tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" | 144 | tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" |
| 145 | depends on SND && PNP && ISA | 145 | depends on PNP |
| 146 | select ISAPNP | 146 | select ISAPNP |
| 147 | select SND_OPL3_LIB | 147 | select SND_OPL3_LIB |
| 148 | select SND_MPU401_UART | 148 | select SND_MPU401_UART |
| @@ -156,7 +156,7 @@ config SND_DT019X | |||
| 156 | 156 | ||
| 157 | config SND_ES968 | 157 | config SND_ES968 |
| 158 | tristate "Generic ESS ES968 driver" | 158 | tristate "Generic ESS ES968 driver" |
| 159 | depends on SND && PNP && ISA | 159 | depends on PNP |
| 160 | select ISAPNP | 160 | select ISAPNP |
| 161 | select SND_MPU401_UART | 161 | select SND_MPU401_UART |
| 162 | select SND_SB8_DSP | 162 | select SND_SB8_DSP |
| @@ -168,7 +168,6 @@ config SND_ES968 | |||
| 168 | 168 | ||
| 169 | config SND_ES1688 | 169 | config SND_ES1688 |
| 170 | tristate "Generic ESS ES688/ES1688 driver" | 170 | tristate "Generic ESS ES688/ES1688 driver" |
| 171 | depends on SND | ||
| 172 | select SND_OPL3_LIB | 171 | select SND_OPL3_LIB |
| 173 | select SND_MPU401_UART | 172 | select SND_MPU401_UART |
| 174 | select SND_PCM | 173 | select SND_PCM |
| @@ -181,7 +180,6 @@ config SND_ES1688 | |||
| 181 | 180 | ||
| 182 | config SND_ES18XX | 181 | config SND_ES18XX |
| 183 | tristate "Generic ESS ES18xx driver" | 182 | tristate "Generic ESS ES18xx driver" |
| 184 | depends on SND | ||
| 185 | select SND_OPL3_LIB | 183 | select SND_OPL3_LIB |
| 186 | select SND_MPU401_UART | 184 | select SND_MPU401_UART |
| 187 | select SND_PCM | 185 | select SND_PCM |
| @@ -193,7 +191,7 @@ config SND_ES18XX | |||
| 193 | 191 | ||
| 194 | config SND_SC6000 | 192 | config SND_SC6000 |
| 195 | tristate "Gallant SC-6000, Audio Excel DSP 16" | 193 | tristate "Gallant SC-6000, Audio Excel DSP 16" |
| 196 | depends on SND && HAS_IOPORT | 194 | depends on HAS_IOPORT |
| 197 | select SND_AD1848_LIB | 195 | select SND_AD1848_LIB |
| 198 | select SND_OPL3_LIB | 196 | select SND_OPL3_LIB |
| 199 | select SND_MPU401_UART | 197 | select SND_MPU401_UART |
| @@ -204,15 +202,10 @@ config SND_SC6000 | |||
| 204 | To compile this driver as a module, choose M here: the module | 202 | To compile this driver as a module, choose M here: the module |
| 205 | will be called snd-sc6000. | 203 | will be called snd-sc6000. |
| 206 | 204 | ||
| 207 | config SND_GUS_SYNTH | ||
| 208 | tristate | ||
| 209 | |||
| 210 | config SND_GUSCLASSIC | 205 | config SND_GUSCLASSIC |
| 211 | tristate "Gravis UltraSound Classic" | 206 | tristate "Gravis UltraSound Classic" |
| 212 | depends on SND | ||
| 213 | select SND_RAWMIDI | 207 | select SND_RAWMIDI |
| 214 | select SND_PCM | 208 | select SND_PCM |
| 215 | select SND_GUS_SYNTH | ||
| 216 | help | 209 | help |
| 217 | Say Y here to include support for Gravis UltraSound Classic | 210 | Say Y here to include support for Gravis UltraSound Classic |
| 218 | soundcards. | 211 | soundcards. |
| @@ -222,11 +215,9 @@ config SND_GUSCLASSIC | |||
| 222 | 215 | ||
| 223 | config SND_GUSEXTREME | 216 | config SND_GUSEXTREME |
| 224 | tristate "Gravis UltraSound Extreme" | 217 | tristate "Gravis UltraSound Extreme" |
| 225 | depends on SND | ||
| 226 | select SND_HWDEP | 218 | select SND_HWDEP |
| 227 | select SND_MPU401_UART | 219 | select SND_MPU401_UART |
| 228 | select SND_PCM | 220 | select SND_PCM |
| 229 | select SND_GUS_SYNTH | ||
| 230 | help | 221 | help |
| 231 | Say Y here to include support for Gravis UltraSound Extreme | 222 | Say Y here to include support for Gravis UltraSound Extreme |
| 232 | soundcards. | 223 | soundcards. |
| @@ -236,10 +227,8 @@ config SND_GUSEXTREME | |||
| 236 | 227 | ||
| 237 | config SND_GUSMAX | 228 | config SND_GUSMAX |
| 238 | tristate "Gravis UltraSound MAX" | 229 | tristate "Gravis UltraSound MAX" |
| 239 | depends on SND | ||
| 240 | select SND_RAWMIDI | 230 | select SND_RAWMIDI |
| 241 | select SND_CS4231_LIB | 231 | select SND_CS4231_LIB |
| 242 | select SND_GUS_SYNTH | ||
| 243 | help | 232 | help |
| 244 | Say Y here to include support for Gravis UltraSound MAX | 233 | Say Y here to include support for Gravis UltraSound MAX |
| 245 | soundcards. | 234 | soundcards. |
| @@ -249,10 +238,9 @@ config SND_GUSMAX | |||
| 249 | 238 | ||
| 250 | config SND_INTERWAVE | 239 | config SND_INTERWAVE |
| 251 | tristate "AMD InterWave, Gravis UltraSound PnP" | 240 | tristate "AMD InterWave, Gravis UltraSound PnP" |
| 252 | depends on SND && PNP && ISA | 241 | depends on PNP |
| 253 | select SND_RAWMIDI | 242 | select SND_RAWMIDI |
| 254 | select SND_CS4231_LIB | 243 | select SND_CS4231_LIB |
| 255 | select SND_GUS_SYNTH | ||
| 256 | help | 244 | help |
| 257 | Say Y here to include support for AMD InterWave based | 245 | Say Y here to include support for AMD InterWave based |
| 258 | soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, | 246 | soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, |
| @@ -263,10 +251,9 @@ config SND_INTERWAVE | |||
| 263 | 251 | ||
| 264 | config SND_INTERWAVE_STB | 252 | config SND_INTERWAVE_STB |
| 265 | tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" | 253 | tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" |
| 266 | depends on SND && PNP && ISA | 254 | depends on PNP |
| 267 | select SND_RAWMIDI | 255 | select SND_RAWMIDI |
| 268 | select SND_CS4231_LIB | 256 | select SND_CS4231_LIB |
| 269 | select SND_GUS_SYNTH | ||
| 270 | help | 257 | help |
| 271 | Say Y here to include support for AMD InterWave based | 258 | Say Y here to include support for AMD InterWave based |
| 272 | soundcards with a TEA6330T bass and treble regulator | 259 | soundcards with a TEA6330T bass and treble regulator |
| @@ -277,7 +264,6 @@ config SND_INTERWAVE_STB | |||
| 277 | 264 | ||
| 278 | config SND_OPL3SA2 | 265 | config SND_OPL3SA2 |
| 279 | tristate "Yamaha OPL3-SA2/SA3" | 266 | tristate "Yamaha OPL3-SA2/SA3" |
| 280 | depends on SND | ||
| 281 | select SND_OPL3_LIB | 267 | select SND_OPL3_LIB |
| 282 | select SND_MPU401_UART | 268 | select SND_MPU401_UART |
| 283 | select SND_CS4231_LIB | 269 | select SND_CS4231_LIB |
| @@ -290,7 +276,6 @@ config SND_OPL3SA2 | |||
| 290 | 276 | ||
| 291 | config SND_OPTI92X_AD1848 | 277 | config SND_OPTI92X_AD1848 |
| 292 | tristate "OPTi 82C92x - AD1848" | 278 | tristate "OPTi 82C92x - AD1848" |
| 293 | depends on SND | ||
| 294 | select SND_OPL3_LIB | 279 | select SND_OPL3_LIB |
| 295 | select SND_OPL4_LIB | 280 | select SND_OPL4_LIB |
| 296 | select SND_MPU401_UART | 281 | select SND_MPU401_UART |
| @@ -304,7 +289,6 @@ config SND_OPTI92X_AD1848 | |||
| 304 | 289 | ||
| 305 | config SND_OPTI92X_CS4231 | 290 | config SND_OPTI92X_CS4231 |
| 306 | tristate "OPTi 82C92x - CS4231" | 291 | tristate "OPTi 82C92x - CS4231" |
| 307 | depends on SND | ||
| 308 | select SND_OPL3_LIB | 292 | select SND_OPL3_LIB |
| 309 | select SND_OPL4_LIB | 293 | select SND_OPL4_LIB |
| 310 | select SND_MPU401_UART | 294 | select SND_MPU401_UART |
| @@ -318,10 +302,9 @@ config SND_OPTI92X_CS4231 | |||
| 318 | 302 | ||
| 319 | config SND_OPTI93X | 303 | config SND_OPTI93X |
| 320 | tristate "OPTi 82C93x" | 304 | tristate "OPTi 82C93x" |
| 321 | depends on SND | ||
| 322 | select SND_OPL3_LIB | 305 | select SND_OPL3_LIB |
| 323 | select SND_MPU401_UART | 306 | select SND_MPU401_UART |
| 324 | select SND_PCM | 307 | select SND_CS4231_LIB |
| 325 | help | 308 | help |
| 326 | Say Y here to include support for soundcards based on Opti | 309 | Say Y here to include support for soundcards based on Opti |
| 327 | 82C93x chips. | 310 | 82C93x chips. |
| @@ -331,7 +314,6 @@ config SND_OPTI93X | |||
| 331 | 314 | ||
| 332 | config SND_MIRO | 315 | config SND_MIRO |
| 333 | tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver" | 316 | tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver" |
| 334 | depends on SND | ||
| 335 | select SND_OPL4_LIB | 317 | select SND_OPL4_LIB |
| 336 | select SND_CS4231_LIB | 318 | select SND_CS4231_LIB |
| 337 | select SND_MPU401_UART | 319 | select SND_MPU401_UART |
| @@ -345,7 +327,6 @@ config SND_MIRO | |||
| 345 | 327 | ||
| 346 | config SND_SB8 | 328 | config SND_SB8 |
| 347 | tristate "Sound Blaster 1.0/2.0/Pro (8-bit)" | 329 | tristate "Sound Blaster 1.0/2.0/Pro (8-bit)" |
| 348 | depends on SND | ||
| 349 | select SND_OPL3_LIB | 330 | select SND_OPL3_LIB |
| 350 | select SND_RAWMIDI | 331 | select SND_RAWMIDI |
| 351 | select SND_SB8_DSP | 332 | select SND_SB8_DSP |
| @@ -358,7 +339,6 @@ config SND_SB8 | |||
| 358 | 339 | ||
| 359 | config SND_SB16 | 340 | config SND_SB16 |
| 360 | tristate "Sound Blaster 16 (PnP)" | 341 | tristate "Sound Blaster 16 (PnP)" |
| 361 | depends on SND | ||
| 362 | select SND_OPL3_LIB | 342 | select SND_OPL3_LIB |
| 363 | select SND_MPU401_UART | 343 | select SND_MPU401_UART |
| 364 | select SND_SB16_DSP | 344 | select SND_SB16_DSP |
| @@ -371,7 +351,6 @@ config SND_SB16 | |||
| 371 | 351 | ||
| 372 | config SND_SBAWE | 352 | config SND_SBAWE |
| 373 | tristate "Sound Blaster AWE (32,64) (PnP)" | 353 | tristate "Sound Blaster AWE (32,64) (PnP)" |
| 374 | depends on SND | ||
| 375 | select SND_OPL3_LIB | 354 | select SND_OPL3_LIB |
| 376 | select SND_MPU401_UART | 355 | select SND_MPU401_UART |
| 377 | select SND_SB16_DSP | 356 | select SND_SB16_DSP |
| @@ -402,7 +381,6 @@ config SND_SB16_CSP_FIRMWARE_IN_KERNEL | |||
| 402 | 381 | ||
| 403 | config SND_SGALAXY | 382 | config SND_SGALAXY |
| 404 | tristate "Aztech Sound Galaxy" | 383 | tristate "Aztech Sound Galaxy" |
| 405 | depends on SND | ||
| 406 | select SND_AD1848_LIB | 384 | select SND_AD1848_LIB |
| 407 | help | 385 | help |
| 408 | Say Y here to include support for Aztech Sound Galaxy | 386 | Say Y here to include support for Aztech Sound Galaxy |
| @@ -413,7 +391,6 @@ config SND_SGALAXY | |||
| 413 | 391 | ||
| 414 | config SND_SSCAPE | 392 | config SND_SSCAPE |
| 415 | tristate "Ensoniq SoundScape PnP driver" | 393 | tristate "Ensoniq SoundScape PnP driver" |
| 416 | depends on SND | ||
| 417 | select SND_HWDEP | 394 | select SND_HWDEP |
| 418 | select SND_MPU401_UART | 395 | select SND_MPU401_UART |
| 419 | select SND_CS4231_LIB | 396 | select SND_CS4231_LIB |
| @@ -426,7 +403,6 @@ config SND_SSCAPE | |||
| 426 | 403 | ||
| 427 | config SND_WAVEFRONT | 404 | config SND_WAVEFRONT |
| 428 | tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" | 405 | tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" |
| 429 | depends on SND | ||
| 430 | select FW_LOADER | 406 | select FW_LOADER |
| 431 | select SND_OPL3_LIB | 407 | select SND_OPL3_LIB |
| 432 | select SND_MPU401_UART | 408 | select SND_MPU401_UART |
| @@ -448,4 +424,5 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL | |||
| 448 | you need to install the firmware files from the | 424 | you need to install the firmware files from the |
| 449 | alsa-firmware package. | 425 | alsa-firmware package. |
| 450 | 426 | ||
| 451 | endmenu | 427 | endif # SND_ISA |
| 428 | |||
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 0aa8649e5c7f..521db705d179 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c | |||
| @@ -119,6 +119,42 @@ static unsigned char snd_cs4231_original_image[32] = | |||
| 119 | 0x00, /* 1f/31 - cbrl */ | 119 | 0x00, /* 1f/31 - cbrl */ |
| 120 | }; | 120 | }; |
| 121 | 121 | ||
| 122 | static unsigned char snd_opti93x_original_image[32] = | ||
| 123 | { | ||
| 124 | 0x00, /* 00/00 - l_mixout_outctrl */ | ||
| 125 | 0x00, /* 01/01 - r_mixout_outctrl */ | ||
| 126 | 0x88, /* 02/02 - l_cd_inctrl */ | ||
| 127 | 0x88, /* 03/03 - r_cd_inctrl */ | ||
| 128 | 0x88, /* 04/04 - l_a1/fm_inctrl */ | ||
| 129 | 0x88, /* 05/05 - r_a1/fm_inctrl */ | ||
| 130 | 0x80, /* 06/06 - l_dac_inctrl */ | ||
| 131 | 0x80, /* 07/07 - r_dac_inctrl */ | ||
| 132 | 0x00, /* 08/08 - ply_dataform_reg */ | ||
| 133 | 0x00, /* 09/09 - if_conf */ | ||
| 134 | 0x00, /* 0a/10 - pin_ctrl */ | ||
| 135 | 0x00, /* 0b/11 - err_init_reg */ | ||
| 136 | 0x0a, /* 0c/12 - id_reg */ | ||
| 137 | 0x00, /* 0d/13 - reserved */ | ||
| 138 | 0x00, /* 0e/14 - ply_upcount_reg */ | ||
| 139 | 0x00, /* 0f/15 - ply_lowcount_reg */ | ||
| 140 | 0x88, /* 10/16 - reserved/l_a1_inctrl */ | ||
| 141 | 0x88, /* 11/17 - reserved/r_a1_inctrl */ | ||
| 142 | 0x88, /* 12/18 - l_line_inctrl */ | ||
| 143 | 0x88, /* 13/19 - r_line_inctrl */ | ||
| 144 | 0x88, /* 14/20 - l_mic_inctrl */ | ||
| 145 | 0x88, /* 15/21 - r_mic_inctrl */ | ||
| 146 | 0x80, /* 16/22 - l_out_outctrl */ | ||
| 147 | 0x80, /* 17/23 - r_out_outctrl */ | ||
| 148 | 0x00, /* 18/24 - reserved */ | ||
| 149 | 0x00, /* 19/25 - reserved */ | ||
| 150 | 0x00, /* 1a/26 - reserved */ | ||
| 151 | 0x00, /* 1b/27 - reserved */ | ||
| 152 | 0x00, /* 1c/28 - cap_dataform_reg */ | ||
| 153 | 0x00, /* 1d/29 - reserved */ | ||
| 154 | 0x00, /* 1e/30 - cap_upcount_reg */ | ||
| 155 | 0x00 /* 1f/31 - cap_lowcount_reg */ | ||
| 156 | }; | ||
| 157 | |||
| 122 | /* | 158 | /* |
| 123 | * Basic I/O functions | 159 | * Basic I/O functions |
| 124 | */ | 160 | */ |
| @@ -895,7 +931,7 @@ static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream) | |||
| 895 | return 0; | 931 | return 0; |
| 896 | } | 932 | } |
| 897 | 933 | ||
| 898 | static void snd_cs4231_overrange(struct snd_cs4231 *chip) | 934 | void snd_cs4231_overrange(struct snd_cs4231 *chip) |
| 899 | { | 935 | { |
| 900 | unsigned long flags; | 936 | unsigned long flags; |
| 901 | unsigned char res; | 937 | unsigned char res; |
| @@ -1054,8 +1090,11 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip) | |||
| 1054 | chip->image[CS4231_IFACE_CTRL] = | 1090 | chip->image[CS4231_IFACE_CTRL] = |
| 1055 | (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | | 1091 | (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | |
| 1056 | (chip->single_dma ? CS4231_SINGLE_DMA : 0); | 1092 | (chip->single_dma ? CS4231_SINGLE_DMA : 0); |
| 1057 | chip->image[CS4231_ALT_FEATURE_1] = 0x80; | 1093 | if (chip->hardware != CS4231_HW_OPTI93X) { |
| 1058 | chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; | 1094 | chip->image[CS4231_ALT_FEATURE_1] = 0x80; |
| 1095 | chip->image[CS4231_ALT_FEATURE_2] = | ||
| 1096 | chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; | ||
| 1097 | } | ||
| 1059 | ptr = (unsigned char *) &chip->image; | 1098 | ptr = (unsigned char *) &chip->image; |
| 1060 | snd_cs4231_mce_down(chip); | 1099 | snd_cs4231_mce_down(chip); |
| 1061 | spin_lock_irqsave(&chip->reg_lock, flags); | 1100 | spin_lock_irqsave(&chip->reg_lock, flags); |
| @@ -1376,6 +1415,7 @@ const char *snd_cs4231_chip_id(struct snd_cs4231 *chip) | |||
| 1376 | case CS4231_HW_INTERWAVE: return "AMD InterWave"; | 1415 | case CS4231_HW_INTERWAVE: return "AMD InterWave"; |
| 1377 | case CS4231_HW_OPL3SA2: return chip->card->shortname; | 1416 | case CS4231_HW_OPL3SA2: return chip->card->shortname; |
| 1378 | case CS4231_HW_AD1845: return "AD1845"; | 1417 | case CS4231_HW_AD1845: return "AD1845"; |
| 1418 | case CS4231_HW_OPTI93X: return "OPTi 93x"; | ||
| 1379 | default: return "???"; | 1419 | default: return "???"; |
| 1380 | } | 1420 | } |
| 1381 | } | 1421 | } |
| @@ -1401,8 +1441,13 @@ static int snd_cs4231_new(struct snd_card *card, | |||
| 1401 | chip->rate_constraint = snd_cs4231_xrate; | 1441 | chip->rate_constraint = snd_cs4231_xrate; |
| 1402 | chip->set_playback_format = snd_cs4231_playback_format; | 1442 | chip->set_playback_format = snd_cs4231_playback_format; |
| 1403 | chip->set_capture_format = snd_cs4231_capture_format; | 1443 | chip->set_capture_format = snd_cs4231_capture_format; |
| 1404 | memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); | 1444 | if (chip->hardware == CS4231_HW_OPTI93X) |
| 1405 | 1445 | memcpy(&chip->image, &snd_opti93x_original_image, | |
| 1446 | sizeof(snd_opti93x_original_image)); | ||
| 1447 | else | ||
| 1448 | memcpy(&chip->image, &snd_cs4231_original_image, | ||
| 1449 | sizeof(snd_cs4231_original_image)); | ||
| 1450 | |||
| 1406 | *rchip = chip; | 1451 | *rchip = chip; |
| 1407 | return 0; | 1452 | return 0; |
| 1408 | } | 1453 | } |
| @@ -1790,6 +1835,48 @@ CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), | |||
| 1790 | CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1) | 1835 | CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1) |
| 1791 | }; | 1836 | }; |
| 1792 | 1837 | ||
| 1838 | static struct snd_kcontrol_new snd_opti93x_controls[] = { | ||
| 1839 | CS4231_DOUBLE("Master Playback Switch", 0, | ||
| 1840 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
| 1841 | CS4231_DOUBLE("Master Playback Volume", 0, | ||
| 1842 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), | ||
| 1843 | CS4231_DOUBLE("PCM Playback Switch", 0, | ||
| 1844 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), | ||
| 1845 | CS4231_DOUBLE("PCM Playback Volume", 0, | ||
| 1846 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), | ||
| 1847 | CS4231_DOUBLE("FM Playback Switch", 0, | ||
| 1848 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1849 | CS4231_DOUBLE("FM Playback Volume", 0, | ||
| 1850 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1851 | CS4231_DOUBLE("Line Playback Switch", 0, | ||
| 1852 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), | ||
| 1853 | CS4231_DOUBLE("Line Playback Volume", 0, | ||
| 1854 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), | ||
| 1855 | CS4231_DOUBLE("Mic Playback Switch", 0, | ||
| 1856 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1857 | CS4231_DOUBLE("Mic Playback Volume", 0, | ||
| 1858 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1859 | CS4231_DOUBLE("Mic Boost", 0, | ||
| 1860 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), | ||
| 1861 | CS4231_DOUBLE("CD Playback Switch", 0, | ||
| 1862 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1863 | CS4231_DOUBLE("CD Playback Volume", 0, | ||
| 1864 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1865 | CS4231_DOUBLE("Aux Playback Switch", 0, | ||
| 1866 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1867 | CS4231_DOUBLE("Aux Playback Volume", 0, | ||
| 1868 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1869 | CS4231_DOUBLE("Capture Volume", 0, | ||
| 1870 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), | ||
| 1871 | { | ||
| 1872 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 1873 | .name = "Capture Source", | ||
| 1874 | .info = snd_cs4231_info_mux, | ||
| 1875 | .get = snd_cs4231_get_mux, | ||
| 1876 | .put = snd_cs4231_put_mux, | ||
| 1877 | } | ||
| 1878 | }; | ||
| 1879 | |||
| 1793 | int snd_cs4231_mixer(struct snd_cs4231 *chip) | 1880 | int snd_cs4231_mixer(struct snd_cs4231 *chip) |
| 1794 | { | 1881 | { |
| 1795 | struct snd_card *card; | 1882 | struct snd_card *card; |
| @@ -1802,10 +1889,22 @@ int snd_cs4231_mixer(struct snd_cs4231 *chip) | |||
| 1802 | 1889 | ||
| 1803 | strcpy(card->mixername, chip->pcm->name); | 1890 | strcpy(card->mixername, chip->pcm->name); |
| 1804 | 1891 | ||
| 1805 | for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { | 1892 | if (chip->hardware == CS4231_HW_OPTI93X) |
| 1806 | if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip))) < 0) | 1893 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { |
| 1807 | return err; | 1894 | err = snd_ctl_add(card, |
| 1808 | } | 1895 | snd_ctl_new1(&snd_opti93x_controls[idx], |
| 1896 | chip)); | ||
| 1897 | if (err < 0) | ||
| 1898 | return err; | ||
| 1899 | } | ||
| 1900 | else | ||
| 1901 | for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { | ||
| 1902 | err = snd_ctl_add(card, | ||
| 1903 | snd_ctl_new1(&snd_cs4231_controls[idx], | ||
| 1904 | chip)); | ||
| 1905 | if (err < 0) | ||
| 1906 | return err; | ||
| 1907 | } | ||
| 1809 | return 0; | 1908 | return 0; |
| 1810 | } | 1909 | } |
| 1811 | 1910 | ||
| @@ -1815,6 +1914,7 @@ EXPORT_SYMBOL(snd_cs4236_ext_out); | |||
| 1815 | EXPORT_SYMBOL(snd_cs4236_ext_in); | 1914 | EXPORT_SYMBOL(snd_cs4236_ext_in); |
| 1816 | EXPORT_SYMBOL(snd_cs4231_mce_up); | 1915 | EXPORT_SYMBOL(snd_cs4231_mce_up); |
| 1817 | EXPORT_SYMBOL(snd_cs4231_mce_down); | 1916 | EXPORT_SYMBOL(snd_cs4231_mce_down); |
| 1917 | EXPORT_SYMBOL(snd_cs4231_overrange); | ||
| 1818 | EXPORT_SYMBOL(snd_cs4231_interrupt); | 1918 | EXPORT_SYMBOL(snd_cs4231_interrupt); |
| 1819 | EXPORT_SYMBOL(snd_cs4231_chip_id); | 1919 | EXPORT_SYMBOL(snd_cs4231_chip_id); |
| 1820 | EXPORT_SYMBOL(snd_cs4231_create); | 1920 | EXPORT_SYMBOL(snd_cs4231_create); |
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index fe1afc13a01d..41c047e665ec 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c | |||
| @@ -33,15 +33,10 @@ | |||
| 33 | #include <asm/io.h> | 33 | #include <asm/io.h> |
| 34 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
| 35 | #include <sound/core.h> | 35 | #include <sound/core.h> |
| 36 | #ifdef CS4231 | 36 | #if defined(CS4231) || defined(OPTi93X) |
| 37 | #include <sound/cs4231.h> | 37 | #include <sound/cs4231.h> |
| 38 | #else | 38 | #else |
| 39 | #ifndef OPTi93X | ||
| 40 | #include <sound/ad1848.h> | 39 | #include <sound/ad1848.h> |
| 41 | #else | ||
| 42 | #include <sound/control.h> | ||
| 43 | #include <sound/pcm.h> | ||
| 44 | #endif /* OPTi93X */ | ||
| 45 | #endif /* CS4231 */ | 40 | #endif /* CS4231 */ |
| 46 | #include <sound/mpu401.h> | 41 | #include <sound/mpu401.h> |
| 47 | #include <sound/opl3.h> | 42 | #include <sound/opl3.h> |
| @@ -109,7 +104,6 @@ module_param(dma2, int, 0444); | |||
| 109 | MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); | 104 | MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); |
| 110 | #endif /* CS4231 || OPTi93X */ | 105 | #endif /* CS4231 || OPTi93X */ |
| 111 | 106 | ||
| 112 | #define OPTi9XX_HW_DETECT 0 | ||
| 113 | #define OPTi9XX_HW_82C928 1 | 107 | #define OPTi9XX_HW_82C928 1 |
| 114 | #define OPTi9XX_HW_82C929 2 | 108 | #define OPTi9XX_HW_82C929 2 |
| 115 | #define OPTi9XX_HW_82C924 3 | 109 | #define OPTi9XX_HW_82C924 3 |
| @@ -123,105 +117,12 @@ MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); | |||
| 123 | 117 | ||
| 124 | #ifdef OPTi93X | 118 | #ifdef OPTi93X |
| 125 | 119 | ||
| 126 | #define OPTi93X_INDEX 0x00 | ||
| 127 | #define OPTi93X_DATA 0x01 | ||
| 128 | #define OPTi93X_STATUS 0x02 | 120 | #define OPTi93X_STATUS 0x02 |
| 129 | #define OPTi93X_DDATA 0x03 | ||
| 130 | #define OPTi93X_PORT(chip, r) ((chip)->port + OPTi93X_##r) | 121 | #define OPTi93X_PORT(chip, r) ((chip)->port + OPTi93X_##r) |
| 131 | 122 | ||
| 132 | #define OPTi93X_MIXOUT_LEFT 0x00 | ||
| 133 | #define OPTi93X_MIXOUT_RIGHT 0x01 | ||
| 134 | #define OPTi93X_CD_LEFT_INPUT 0x02 | ||
| 135 | #define OPTi93X_CD_RIGHT_INPUT 0x03 | ||
| 136 | #define OPTi930_AUX_LEFT_INPUT 0x04 | ||
| 137 | #define OPTi930_AUX_RIGHT_INPUT 0x05 | ||
| 138 | #define OPTi931_FM_LEFT_INPUT 0x04 | ||
| 139 | #define OPTi931_FM_RIGHT_INPUT 0x05 | ||
| 140 | #define OPTi93X_DAC_LEFT 0x06 | ||
| 141 | #define OPTi93X_DAC_RIGHT 0x07 | ||
| 142 | #define OPTi93X_PLAY_FORMAT 0x08 | ||
| 143 | #define OPTi93X_IFACE_CONF 0x09 | ||
| 144 | #define OPTi93X_PIN_CTRL 0x0a | ||
| 145 | #define OPTi93X_ERR_INIT 0x0b | ||
| 146 | #define OPTi93X_ID 0x0c | ||
| 147 | #define OPTi93X_PLAY_UPR_CNT 0x0e | ||
| 148 | #define OPTi93X_PLAY_LWR_CNT 0x0f | ||
| 149 | #define OPTi931_AUX_LEFT_INPUT 0x10 | ||
| 150 | #define OPTi931_AUX_RIGHT_INPUT 0x11 | ||
| 151 | #define OPTi93X_LINE_LEFT_INPUT 0x12 | ||
| 152 | #define OPTi93X_LINE_RIGHT_INPUT 0x13 | ||
| 153 | #define OPTi93X_MIC_LEFT_INPUT 0x14 | ||
| 154 | #define OPTi93X_MIC_RIGHT_INPUT 0x15 | ||
| 155 | #define OPTi93X_OUT_LEFT 0x16 | ||
| 156 | #define OPTi93X_OUT_RIGHT 0x17 | ||
| 157 | #define OPTi93X_CAPT_FORMAT 0x1c | ||
| 158 | #define OPTi93X_CAPT_UPR_CNT 0x1e | ||
| 159 | #define OPTi93X_CAPT_LWR_CNT 0x1f | ||
| 160 | |||
| 161 | #define OPTi93X_TRD 0x20 | ||
| 162 | #define OPTi93X_MCE 0x40 | ||
| 163 | #define OPTi93X_INIT 0x80 | ||
| 164 | |||
| 165 | #define OPTi93X_MIXOUT_MIC_GAIN 0x20 | ||
| 166 | #define OPTi93X_MIXOUT_LINE 0x00 | ||
| 167 | #define OPTi93X_MIXOUT_CD 0x40 | ||
| 168 | #define OPTi93X_MIXOUT_MIC 0x80 | ||
| 169 | #define OPTi93X_MIXOUT_MIXER 0xc0 | ||
| 170 | |||
| 171 | #define OPTi93X_STEREO 0x10 | ||
| 172 | #define OPTi93X_LINEAR_8 0x00 | ||
| 173 | #define OPTi93X_ULAW_8 0x20 | ||
| 174 | #define OPTi93X_LINEAR_16_LIT 0x40 | ||
| 175 | #define OPTi93X_ALAW_8 0x60 | ||
| 176 | #define OPTi93X_ADPCM_16 0xa0 | ||
| 177 | #define OPTi93X_LINEAR_16_BIG 0xc0 | ||
| 178 | |||
| 179 | #define OPTi93X_CAPTURE_PIO 0x80 | ||
| 180 | #define OPTi93X_PLAYBACK_PIO 0x40 | ||
| 181 | #define OPTi93X_AUTOCALIB 0x08 | ||
| 182 | #define OPTi93X_SINGLE_DMA 0x04 | ||
| 183 | #define OPTi93X_CAPTURE_ENABLE 0x02 | ||
| 184 | #define OPTi93X_PLAYBACK_ENABLE 0x01 | ||
| 185 | |||
| 186 | #define OPTi93X_IRQ_ENABLE 0x02 | ||
| 187 | |||
| 188 | #define OPTi93X_DMA_REQUEST 0x10 | ||
| 189 | #define OPTi93X_CALIB_IN_PROGRESS 0x20 | ||
| 190 | |||
| 191 | #define OPTi93X_IRQ_PLAYBACK 0x04 | 123 | #define OPTi93X_IRQ_PLAYBACK 0x04 |
| 192 | #define OPTi93X_IRQ_CAPTURE 0x08 | 124 | #define OPTi93X_IRQ_CAPTURE 0x08 |
| 193 | 125 | ||
| 194 | |||
| 195 | struct snd_opti93x { | ||
| 196 | unsigned long port; | ||
| 197 | struct resource *res_port; | ||
| 198 | int irq; | ||
| 199 | int dma1; | ||
| 200 | int dma2; | ||
| 201 | |||
| 202 | struct snd_opti9xx *chip; | ||
| 203 | unsigned short hardware; | ||
| 204 | unsigned char image[32]; | ||
| 205 | |||
| 206 | unsigned char mce_bit; | ||
| 207 | unsigned short mode; | ||
| 208 | int mute; | ||
| 209 | |||
| 210 | spinlock_t lock; | ||
| 211 | |||
| 212 | struct snd_card *card; | ||
| 213 | struct snd_pcm *pcm; | ||
| 214 | struct snd_pcm_substream *playback_substream; | ||
| 215 | struct snd_pcm_substream *capture_substream; | ||
| 216 | unsigned int p_dma_size; | ||
| 217 | unsigned int c_dma_size; | ||
| 218 | }; | ||
| 219 | |||
| 220 | #define OPTi93X_MODE_NONE 0x00 | ||
| 221 | #define OPTi93X_MODE_PLAY 0x01 | ||
| 222 | #define OPTi93X_MODE_CAPTURE 0x02 | ||
| 223 | #define OPTi93X_MODE_OPEN (OPTi93X_MODE_PLAY | OPTi93X_MODE_CAPTURE) | ||
| 224 | |||
| 225 | #endif /* OPTi93X */ | 126 | #endif /* OPTi93X */ |
| 226 | 127 | ||
| 227 | struct snd_opti9xx { | 128 | struct snd_opti9xx { |
| @@ -234,6 +135,7 @@ struct snd_opti9xx { | |||
| 234 | unsigned long mc_base_size; | 135 | unsigned long mc_base_size; |
| 235 | #ifdef OPTi93X | 136 | #ifdef OPTi93X |
| 236 | unsigned long mc_indir_index; | 137 | unsigned long mc_indir_index; |
| 138 | struct snd_cs4231 *codec; | ||
| 237 | #endif /* OPTi93X */ | 139 | #endif /* OPTi93X */ |
| 238 | unsigned long pwd_reg; | 140 | unsigned long pwd_reg; |
| 239 | 141 | ||
| @@ -491,16 +393,9 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) | |||
| 491 | break; | 393 | break; |
| 492 | 394 | ||
| 493 | #else /* OPTi93X */ | 395 | #else /* OPTi93X */ |
| 494 | case OPTi9XX_HW_82C930: | ||
| 495 | case OPTi9XX_HW_82C931: | 396 | case OPTi9XX_HW_82C931: |
| 496 | case OPTi9XX_HW_82C933: | 397 | case OPTi9XX_HW_82C933: |
| 497 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); | 398 | /* |
| 498 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); | ||
| 499 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | | ||
| 500 | (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), | ||
| 501 | 0x34); | ||
| 502 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); | ||
| 503 | /* | ||
| 504 | * The BTC 1817DW has QS1000 wavetable which is connected | 399 | * The BTC 1817DW has QS1000 wavetable which is connected |
| 505 | * to the serial digital input of the OPTI931. | 400 | * to the serial digital input of the OPTI931. |
| 506 | */ | 401 | */ |
| @@ -510,6 +405,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) | |||
| 510 | * or digital input signal. | 405 | * or digital input signal. |
| 511 | */ | 406 | */ |
| 512 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); | 407 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); |
| 408 | case OPTi9XX_HW_82C930: /* FALL THROUGH */ | ||
| 409 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); | ||
| 410 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); | ||
| 411 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | | ||
| 412 | (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), | ||
| 413 | 0x34); | ||
| 414 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); | ||
| 513 | break; | 415 | break; |
| 514 | #endif /* OPTi93X */ | 416 | #endif /* OPTi93X */ |
| 515 | 417 | ||
| @@ -654,979 +556,23 @@ __skip_mpu: | |||
| 654 | 556 | ||
| 655 | #ifdef OPTi93X | 557 | #ifdef OPTi93X |
| 656 | 558 | ||
| 657 | static unsigned char snd_opti93x_default_image[32] = | ||
| 658 | { | ||
| 659 | 0x00, /* 00/00 - l_mixout_outctrl */ | ||
| 660 | 0x00, /* 01/01 - r_mixout_outctrl */ | ||
| 661 | 0x88, /* 02/02 - l_cd_inctrl */ | ||
| 662 | 0x88, /* 03/03 - r_cd_inctrl */ | ||
| 663 | 0x88, /* 04/04 - l_a1/fm_inctrl */ | ||
| 664 | 0x88, /* 05/05 - r_a1/fm_inctrl */ | ||
| 665 | 0x80, /* 06/06 - l_dac_inctrl */ | ||
| 666 | 0x80, /* 07/07 - r_dac_inctrl */ | ||
| 667 | 0x00, /* 08/08 - ply_dataform_reg */ | ||
| 668 | 0x00, /* 09/09 - if_conf */ | ||
| 669 | 0x00, /* 0a/10 - pin_ctrl */ | ||
| 670 | 0x00, /* 0b/11 - err_init_reg */ | ||
| 671 | 0x0a, /* 0c/12 - id_reg */ | ||
| 672 | 0x00, /* 0d/13 - reserved */ | ||
| 673 | 0x00, /* 0e/14 - ply_upcount_reg */ | ||
| 674 | 0x00, /* 0f/15 - ply_lowcount_reg */ | ||
| 675 | 0x88, /* 10/16 - reserved/l_a1_inctrl */ | ||
| 676 | 0x88, /* 11/17 - reserved/r_a1_inctrl */ | ||
| 677 | 0x88, /* 12/18 - l_line_inctrl */ | ||
| 678 | 0x88, /* 13/19 - r_line_inctrl */ | ||
| 679 | 0x88, /* 14/20 - l_mic_inctrl */ | ||
| 680 | 0x88, /* 15/21 - r_mic_inctrl */ | ||
| 681 | 0x80, /* 16/22 - l_out_outctrl */ | ||
| 682 | 0x80, /* 17/23 - r_out_outctrl */ | ||
| 683 | 0x00, /* 18/24 - reserved */ | ||
| 684 | 0x00, /* 19/25 - reserved */ | ||
| 685 | 0x00, /* 1a/26 - reserved */ | ||
| 686 | 0x00, /* 1b/27 - reserved */ | ||
| 687 | 0x00, /* 1c/28 - cap_dataform_reg */ | ||
| 688 | 0x00, /* 1d/29 - reserved */ | ||
| 689 | 0x00, /* 1e/30 - cap_upcount_reg */ | ||
| 690 | 0x00 /* 1f/31 - cap_lowcount_reg */ | ||
| 691 | }; | ||
| 692 | |||
| 693 | |||
| 694 | static int snd_opti93x_busy_wait(struct snd_opti93x *chip) | ||
| 695 | { | ||
| 696 | int timeout; | ||
| 697 | |||
| 698 | for (timeout = 250; timeout-- > 0; udelay(10)) | ||
| 699 | if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_INIT)) | ||
| 700 | return 0; | ||
| 701 | |||
| 702 | snd_printk("chip still busy.\n"); | ||
| 703 | return -EBUSY; | ||
| 704 | } | ||
| 705 | |||
| 706 | static unsigned char snd_opti93x_in(struct snd_opti93x *chip, unsigned char reg) | ||
| 707 | { | ||
| 708 | snd_opti93x_busy_wait(chip); | ||
| 709 | outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); | ||
| 710 | return inb(OPTi93X_PORT(chip, DATA)); | ||
| 711 | } | ||
| 712 | |||
| 713 | static void snd_opti93x_out(struct snd_opti93x *chip, unsigned char reg, | ||
| 714 | unsigned char value) | ||
| 715 | { | ||
| 716 | snd_opti93x_busy_wait(chip); | ||
| 717 | outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); | ||
| 718 | outb(value, OPTi93X_PORT(chip, DATA)); | ||
| 719 | } | ||
| 720 | |||
| 721 | static void snd_opti93x_out_image(struct snd_opti93x *chip, unsigned char reg, | ||
| 722 | unsigned char value) | ||
| 723 | { | ||
| 724 | snd_opti93x_out(chip, reg, chip->image[reg] = value); | ||
| 725 | } | ||
| 726 | |||
| 727 | static void snd_opti93x_out_mask(struct snd_opti93x *chip, unsigned char reg, | ||
| 728 | unsigned char mask, unsigned char value) | ||
| 729 | { | ||
| 730 | snd_opti93x_out_image(chip, reg, | ||
| 731 | (chip->image[reg] & ~mask) | (value & mask)); | ||
| 732 | } | ||
| 733 | |||
| 734 | |||
| 735 | static void snd_opti93x_mce_up(struct snd_opti93x *chip) | ||
| 736 | { | ||
| 737 | snd_opti93x_busy_wait(chip); | ||
| 738 | |||
| 739 | chip->mce_bit = OPTi93X_MCE; | ||
| 740 | if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE)) | ||
| 741 | outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); | ||
| 742 | } | ||
| 743 | |||
| 744 | static void snd_opti93x_mce_down(struct snd_opti93x *chip) | ||
| 745 | { | ||
| 746 | snd_opti93x_busy_wait(chip); | ||
| 747 | |||
| 748 | chip->mce_bit = 0; | ||
| 749 | if (inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE) | ||
| 750 | outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); | ||
| 751 | } | ||
| 752 | |||
| 753 | #define snd_opti93x_mute_reg(chip, reg, mute) \ | ||
| 754 | snd_opti93x_out(chip, reg, mute ? 0x80 : chip->image[reg]); | ||
| 755 | |||
| 756 | static void snd_opti93x_mute(struct snd_opti93x *chip, int mute) | ||
| 757 | { | ||
| 758 | mute = mute ? 1 : 0; | ||
| 759 | if (chip->mute == mute) | ||
| 760 | return; | ||
| 761 | |||
| 762 | chip->mute = mute; | ||
| 763 | |||
| 764 | snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute); | ||
| 765 | snd_opti93x_mute_reg(chip, OPTi93X_CD_RIGHT_INPUT, mute); | ||
| 766 | switch (chip->hardware) { | ||
| 767 | case OPTi9XX_HW_82C930: | ||
| 768 | snd_opti93x_mute_reg(chip, OPTi930_AUX_LEFT_INPUT, mute); | ||
| 769 | snd_opti93x_mute_reg(chip, OPTi930_AUX_RIGHT_INPUT, mute); | ||
| 770 | break; | ||
| 771 | case OPTi9XX_HW_82C931: | ||
| 772 | case OPTi9XX_HW_82C933: | ||
| 773 | snd_opti93x_mute_reg(chip, OPTi931_FM_LEFT_INPUT, mute); | ||
| 774 | snd_opti93x_mute_reg(chip, OPTi931_FM_RIGHT_INPUT, mute); | ||
| 775 | snd_opti93x_mute_reg(chip, OPTi931_AUX_LEFT_INPUT, mute); | ||
| 776 | snd_opti93x_mute_reg(chip, OPTi931_AUX_RIGHT_INPUT, mute); | ||
| 777 | } | ||
| 778 | snd_opti93x_mute_reg(chip, OPTi93X_DAC_LEFT, mute); | ||
| 779 | snd_opti93x_mute_reg(chip, OPTi93X_DAC_RIGHT, mute); | ||
| 780 | snd_opti93x_mute_reg(chip, OPTi93X_LINE_LEFT_INPUT, mute); | ||
| 781 | snd_opti93x_mute_reg(chip, OPTi93X_LINE_RIGHT_INPUT, mute); | ||
| 782 | snd_opti93x_mute_reg(chip, OPTi93X_MIC_LEFT_INPUT, mute); | ||
| 783 | snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute); | ||
| 784 | snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute); | ||
| 785 | snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute); | ||
| 786 | } | ||
| 787 | |||
| 788 | |||
| 789 | static unsigned int snd_opti93x_get_count(unsigned char format, | ||
| 790 | unsigned int size) | ||
| 791 | { | ||
| 792 | switch (format & 0xe0) { | ||
| 793 | case OPTi93X_LINEAR_16_LIT: | ||
| 794 | case OPTi93X_LINEAR_16_BIG: | ||
| 795 | size >>= 1; | ||
| 796 | break; | ||
| 797 | case OPTi93X_ADPCM_16: | ||
| 798 | return size >> 2; | ||
| 799 | } | ||
| 800 | return (format & OPTi93X_STEREO) ? (size >> 1) : size; | ||
| 801 | } | ||
| 802 | |||
| 803 | static unsigned int rates[] = { 5512, 6615, 8000, 9600, 11025, 16000, | ||
| 804 | 18900, 22050, 27428, 32000, 33075, 37800, | ||
| 805 | 44100, 48000 }; | ||
| 806 | #define RATES ARRAY_SIZE(rates) | ||
| 807 | |||
| 808 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { | ||
| 809 | .count = RATES, | ||
| 810 | .list = rates, | ||
| 811 | .mask = 0, | ||
| 812 | }; | ||
| 813 | |||
| 814 | static unsigned char bits[] = { 0x01, 0x0f, 0x00, 0x0e, 0x03, 0x02, | ||
| 815 | 0x05, 0x07, 0x04, 0x06, 0x0d, 0x09, | ||
| 816 | 0x0b, 0x0c}; | ||
| 817 | |||
| 818 | static unsigned char snd_opti93x_get_freq(unsigned int rate) | ||
| 819 | { | ||
| 820 | unsigned int i; | ||
| 821 | |||
| 822 | for (i = 0; i < RATES; i++) { | ||
| 823 | if (rate == rates[i]) | ||
| 824 | return bits[i]; | ||
| 825 | } | ||
| 826 | snd_BUG(); | ||
| 827 | return bits[RATES-1]; | ||
| 828 | } | ||
| 829 | |||
| 830 | static unsigned char snd_opti93x_get_format(struct snd_opti93x *chip, | ||
| 831 | unsigned int format, int channels) | ||
| 832 | { | ||
| 833 | unsigned char retval = OPTi93X_LINEAR_8; | ||
| 834 | |||
| 835 | switch (format) { | ||
| 836 | case SNDRV_PCM_FORMAT_MU_LAW: | ||
| 837 | retval = OPTi93X_ULAW_8; | ||
| 838 | break; | ||
| 839 | case SNDRV_PCM_FORMAT_A_LAW: | ||
| 840 | retval = OPTi93X_ALAW_8; | ||
| 841 | break; | ||
| 842 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 843 | retval = OPTi93X_LINEAR_16_LIT; | ||
| 844 | break; | ||
| 845 | case SNDRV_PCM_FORMAT_S16_BE: | ||
| 846 | retval = OPTi93X_LINEAR_16_BIG; | ||
| 847 | break; | ||
| 848 | case SNDRV_PCM_FORMAT_IMA_ADPCM: | ||
| 849 | retval = OPTi93X_ADPCM_16; | ||
| 850 | } | ||
| 851 | return (channels > 1) ? (retval | OPTi93X_STEREO) : retval; | ||
| 852 | } | ||
| 853 | |||
| 854 | |||
| 855 | static void snd_opti93x_playback_format(struct snd_opti93x *chip, unsigned char fmt) | ||
| 856 | { | ||
| 857 | unsigned char mask; | ||
| 858 | |||
| 859 | snd_opti93x_mute(chip, 1); | ||
| 860 | |||
| 861 | snd_opti93x_mce_up(chip); | ||
| 862 | mask = (chip->mode & OPTi93X_MODE_CAPTURE) ? 0xf0 : 0xff; | ||
| 863 | snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, mask, fmt); | ||
| 864 | snd_opti93x_mce_down(chip); | ||
| 865 | |||
| 866 | snd_opti93x_mute(chip, 0); | ||
| 867 | } | ||
| 868 | |||
| 869 | static void snd_opti93x_capture_format(struct snd_opti93x *chip, unsigned char fmt) | ||
| 870 | { | ||
| 871 | snd_opti93x_mute(chip, 1); | ||
| 872 | |||
| 873 | snd_opti93x_mce_up(chip); | ||
| 874 | if (!(chip->mode & OPTi93X_MODE_PLAY)) | ||
| 875 | snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, 0x0f, fmt); | ||
| 876 | else | ||
| 877 | fmt = chip->image[OPTi93X_PLAY_FORMAT] & 0xf0; | ||
| 878 | snd_opti93x_out_image(chip, OPTi93X_CAPT_FORMAT, fmt); | ||
| 879 | snd_opti93x_mce_down(chip); | ||
| 880 | |||
| 881 | snd_opti93x_mute(chip, 0); | ||
| 882 | } | ||
| 883 | |||
| 884 | |||
| 885 | static int snd_opti93x_open(struct snd_opti93x *chip, unsigned int mode) | ||
| 886 | { | ||
| 887 | unsigned long flags; | ||
| 888 | |||
| 889 | spin_lock_irqsave(&chip->lock, flags); | ||
| 890 | |||
| 891 | if (chip->mode & mode) { | ||
| 892 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 893 | return -EAGAIN; | ||
| 894 | } | ||
| 895 | |||
| 896 | if (!(chip->mode & OPTi93X_MODE_OPEN)) { | ||
| 897 | outb(0x00, OPTi93X_PORT(chip, STATUS)); | ||
| 898 | snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, | ||
| 899 | OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE); | ||
| 900 | chip->mode = mode; | ||
| 901 | } | ||
| 902 | else | ||
| 903 | chip->mode |= mode; | ||
| 904 | |||
| 905 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 906 | return 0; | ||
| 907 | } | ||
| 908 | |||
| 909 | static void snd_opti93x_close(struct snd_opti93x *chip, unsigned int mode) | ||
| 910 | { | ||
| 911 | unsigned long flags; | ||
| 912 | |||
| 913 | spin_lock_irqsave(&chip->lock, flags); | ||
| 914 | |||
| 915 | chip->mode &= ~mode; | ||
| 916 | if (chip->mode & OPTi93X_MODE_OPEN) { | ||
| 917 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 918 | return; | ||
| 919 | } | ||
| 920 | |||
| 921 | snd_opti93x_mute(chip, 1); | ||
| 922 | |||
| 923 | outb(0, OPTi93X_PORT(chip, STATUS)); | ||
| 924 | snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, | ||
| 925 | ~OPTi93X_IRQ_ENABLE); | ||
| 926 | |||
| 927 | snd_opti93x_mce_up(chip); | ||
| 928 | snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00); | ||
| 929 | snd_opti93x_mce_down(chip); | ||
| 930 | chip->mode = 0; | ||
| 931 | |||
| 932 | snd_opti93x_mute(chip, 0); | ||
| 933 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 934 | } | ||
| 935 | |||
| 936 | static int snd_opti93x_trigger(struct snd_pcm_substream *substream, | ||
| 937 | unsigned char what, int cmd) | ||
| 938 | { | ||
| 939 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 940 | |||
| 941 | switch (cmd) { | ||
| 942 | case SNDRV_PCM_TRIGGER_START: | ||
| 943 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 944 | { | ||
| 945 | unsigned int what = 0; | ||
| 946 | struct snd_pcm_substream *s; | ||
| 947 | snd_pcm_group_for_each_entry(s, substream) { | ||
| 948 | if (s == chip->playback_substream) { | ||
| 949 | what |= OPTi93X_PLAYBACK_ENABLE; | ||
| 950 | snd_pcm_trigger_done(s, substream); | ||
| 951 | } else if (s == chip->capture_substream) { | ||
| 952 | what |= OPTi93X_CAPTURE_ENABLE; | ||
| 953 | snd_pcm_trigger_done(s, substream); | ||
| 954 | } | ||
| 955 | } | ||
| 956 | spin_lock(&chip->lock); | ||
| 957 | if (cmd == SNDRV_PCM_TRIGGER_START) { | ||
| 958 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what); | ||
| 959 | if (what & OPTi93X_CAPTURE_ENABLE) | ||
| 960 | udelay(50); | ||
| 961 | } else | ||
| 962 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00); | ||
| 963 | spin_unlock(&chip->lock); | ||
| 964 | break; | ||
| 965 | } | ||
| 966 | default: | ||
| 967 | return -EINVAL; | ||
| 968 | } | ||
| 969 | return 0; | ||
| 970 | } | ||
| 971 | |||
| 972 | static int snd_opti93x_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 973 | { | ||
| 974 | return snd_opti93x_trigger(substream, | ||
| 975 | OPTi93X_PLAYBACK_ENABLE, cmd); | ||
| 976 | } | ||
| 977 | |||
| 978 | static int snd_opti93x_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 979 | { | ||
| 980 | return snd_opti93x_trigger(substream, | ||
| 981 | OPTi93X_CAPTURE_ENABLE, cmd); | ||
| 982 | } | ||
| 983 | |||
| 984 | static int snd_opti93x_hw_params(struct snd_pcm_substream *substream, | ||
| 985 | struct snd_pcm_hw_params *hw_params) | ||
| 986 | { | ||
| 987 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | ||
| 988 | } | ||
| 989 | |||
| 990 | |||
| 991 | static int snd_opti93x_hw_free(struct snd_pcm_substream *substream) | ||
| 992 | { | ||
| 993 | snd_pcm_lib_free_pages(substream); | ||
| 994 | return 0; | ||
| 995 | } | ||
| 996 | |||
| 997 | |||
| 998 | static int snd_opti93x_playback_prepare(struct snd_pcm_substream *substream) | ||
| 999 | { | ||
| 1000 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1001 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 1002 | unsigned long flags; | ||
| 1003 | unsigned char format; | ||
| 1004 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
| 1005 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
| 1006 | |||
| 1007 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1008 | |||
| 1009 | chip->p_dma_size = size; | ||
| 1010 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, | ||
| 1011 | OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO, | ||
| 1012 | ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO)); | ||
| 1013 | |||
| 1014 | snd_dma_program(chip->dma1, runtime->dma_addr, size, | ||
| 1015 | DMA_MODE_WRITE | DMA_AUTOINIT); | ||
| 1016 | |||
| 1017 | format = snd_opti93x_get_freq(runtime->rate); | ||
| 1018 | format |= snd_opti93x_get_format(chip, runtime->format, | ||
| 1019 | runtime->channels); | ||
| 1020 | snd_opti93x_playback_format(chip, format); | ||
| 1021 | format = chip->image[OPTi93X_PLAY_FORMAT]; | ||
| 1022 | |||
| 1023 | count = snd_opti93x_get_count(format, count) - 1; | ||
| 1024 | snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count); | ||
| 1025 | snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8); | ||
| 1026 | |||
| 1027 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1028 | return 0; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | static int snd_opti93x_capture_prepare(struct snd_pcm_substream *substream) | ||
| 1032 | { | ||
| 1033 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1034 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 1035 | unsigned long flags; | ||
| 1036 | unsigned char format; | ||
| 1037 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
| 1038 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
| 1039 | |||
| 1040 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1041 | |||
| 1042 | chip->c_dma_size = size; | ||
| 1043 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, | ||
| 1044 | OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0); | ||
| 1045 | |||
| 1046 | snd_dma_program(chip->dma2, runtime->dma_addr, size, | ||
| 1047 | DMA_MODE_READ | DMA_AUTOINIT); | ||
| 1048 | |||
| 1049 | format = snd_opti93x_get_freq(runtime->rate); | ||
| 1050 | format |= snd_opti93x_get_format(chip, runtime->format, | ||
| 1051 | runtime->channels); | ||
| 1052 | snd_opti93x_capture_format(chip, format); | ||
| 1053 | format = chip->image[OPTi93X_CAPT_FORMAT]; | ||
| 1054 | |||
| 1055 | count = snd_opti93x_get_count(format, count) - 1; | ||
| 1056 | snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count); | ||
| 1057 | snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8); | ||
| 1058 | |||
| 1059 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1060 | return 0; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | static snd_pcm_uframes_t snd_opti93x_playback_pointer(struct snd_pcm_substream *substream) | ||
| 1064 | { | ||
| 1065 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1066 | size_t ptr; | ||
| 1067 | |||
| 1068 | if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE)) | ||
| 1069 | return 0; | ||
| 1070 | |||
| 1071 | ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); | ||
| 1072 | return bytes_to_frames(substream->runtime, ptr); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | static snd_pcm_uframes_t snd_opti93x_capture_pointer(struct snd_pcm_substream *substream) | ||
| 1076 | { | ||
| 1077 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1078 | size_t ptr; | ||
| 1079 | |||
| 1080 | if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_CAPTURE_ENABLE)) | ||
| 1081 | return 0; | ||
| 1082 | |||
| 1083 | ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size); | ||
| 1084 | return bytes_to_frames(substream->runtime, ptr); | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | |||
| 1088 | static void snd_opti93x_overrange(struct snd_opti93x *chip) | ||
| 1089 | { | ||
| 1090 | unsigned long flags; | ||
| 1091 | |||
| 1092 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1093 | |||
| 1094 | if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02)) | ||
| 1095 | chip->capture_substream->runtime->overrange++; | ||
| 1096 | |||
| 1097 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) | 559 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) |
| 1101 | { | 560 | { |
| 1102 | struct snd_opti93x *codec = dev_id; | 561 | struct snd_cs4231 *codec = dev_id; |
| 562 | struct snd_opti9xx *chip = codec->card->private_data; | ||
| 1103 | unsigned char status; | 563 | unsigned char status; |
| 1104 | 564 | ||
| 1105 | status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11)); | 565 | status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11)); |
| 1106 | if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) | 566 | if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) |
| 1107 | snd_pcm_period_elapsed(codec->playback_substream); | 567 | snd_pcm_period_elapsed(codec->playback_substream); |
| 1108 | if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { | 568 | if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { |
| 1109 | snd_opti93x_overrange(codec); | 569 | snd_cs4231_overrange(codec); |
| 1110 | snd_pcm_period_elapsed(codec->capture_substream); | 570 | snd_pcm_period_elapsed(codec->capture_substream); |
| 1111 | } | 571 | } |
| 1112 | outb(0x00, OPTi93X_PORT(codec, STATUS)); | 572 | outb(0x00, OPTi93X_PORT(codec, STATUS)); |
| 1113 | return IRQ_HANDLED; | 573 | return IRQ_HANDLED; |
| 1114 | } | 574 | } |
| 1115 | 575 | ||
| 1116 | |||
| 1117 | static struct snd_pcm_hardware snd_opti93x_playback = { | ||
| 1118 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 1119 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), | ||
| 1120 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | | ||
| 1121 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), | ||
| 1122 | .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, | ||
| 1123 | .rate_min = 5512, | ||
| 1124 | .rate_max = 48000, | ||
| 1125 | .channels_min = 1, | ||
| 1126 | .channels_max = 2, | ||
| 1127 | .buffer_bytes_max = (128*1024), | ||
| 1128 | .period_bytes_min = 64, | ||
| 1129 | .period_bytes_max = (128*1024), | ||
| 1130 | .periods_min = 1, | ||
| 1131 | .periods_max = 1024, | ||
| 1132 | .fifo_size = 0, | ||
| 1133 | }; | ||
| 1134 | |||
| 1135 | static struct snd_pcm_hardware snd_opti93x_capture = { | ||
| 1136 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 1137 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), | ||
| 1138 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | | ||
| 1139 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), | ||
| 1140 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
| 1141 | .rate_min = 5512, | ||
| 1142 | .rate_max = 48000, | ||
| 1143 | .channels_min = 1, | ||
| 1144 | .channels_max = 2, | ||
| 1145 | .buffer_bytes_max = (128*1024), | ||
| 1146 | .period_bytes_min = 64, | ||
| 1147 | .period_bytes_max = (128*1024), | ||
| 1148 | .periods_min = 1, | ||
| 1149 | .periods_max = 1024, | ||
| 1150 | .fifo_size = 0, | ||
| 1151 | }; | ||
| 1152 | |||
| 1153 | static int snd_opti93x_playback_open(struct snd_pcm_substream *substream) | ||
| 1154 | { | ||
| 1155 | int error; | ||
| 1156 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1157 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 1158 | |||
| 1159 | if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0) | ||
| 1160 | return error; | ||
| 1161 | snd_pcm_set_sync(substream); | ||
| 1162 | chip->playback_substream = substream; | ||
| 1163 | runtime->hw = snd_opti93x_playback; | ||
| 1164 | snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); | ||
| 1165 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
| 1166 | return error; | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | static int snd_opti93x_capture_open(struct snd_pcm_substream *substream) | ||
| 1170 | { | ||
| 1171 | int error; | ||
| 1172 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1173 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 1174 | |||
| 1175 | if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0) | ||
| 1176 | return error; | ||
| 1177 | runtime->hw = snd_opti93x_capture; | ||
| 1178 | snd_pcm_set_sync(substream); | ||
| 1179 | chip->capture_substream = substream; | ||
| 1180 | snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); | ||
| 1181 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
| 1182 | return error; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | static int snd_opti93x_playback_close(struct snd_pcm_substream *substream) | ||
| 1186 | { | ||
| 1187 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1188 | |||
| 1189 | chip->playback_substream = NULL; | ||
| 1190 | snd_opti93x_close(chip, OPTi93X_MODE_PLAY); | ||
| 1191 | return 0; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | static int snd_opti93x_capture_close(struct snd_pcm_substream *substream) | ||
| 1195 | { | ||
| 1196 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
| 1197 | |||
| 1198 | chip->capture_substream = NULL; | ||
| 1199 | snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE); | ||
| 1200 | return 0; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | |||
| 1204 | static void snd_opti93x_init(struct snd_opti93x *chip) | ||
| 1205 | { | ||
| 1206 | unsigned long flags; | ||
| 1207 | int i; | ||
| 1208 | |||
| 1209 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1210 | snd_opti93x_mce_up(chip); | ||
| 1211 | |||
| 1212 | for (i = 0; i < 32; i++) | ||
| 1213 | snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]); | ||
| 1214 | |||
| 1215 | snd_opti93x_mce_down(chip); | ||
| 1216 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | static int snd_opti93x_probe(struct snd_opti93x *chip) | ||
| 1220 | { | ||
| 1221 | unsigned long flags; | ||
| 1222 | unsigned char val; | ||
| 1223 | |||
| 1224 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1225 | val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f; | ||
| 1226 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1227 | |||
| 1228 | return (val == 0x0a) ? 0 : -ENODEV; | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | static int snd_opti93x_free(struct snd_opti93x *chip) | ||
| 1232 | { | ||
| 1233 | release_and_free_resource(chip->res_port); | ||
| 1234 | if (chip->dma1 >= 0) { | ||
| 1235 | disable_dma(chip->dma1); | ||
| 1236 | free_dma(chip->dma1); | ||
| 1237 | } | ||
| 1238 | if (chip->dma2 >= 0) { | ||
| 1239 | disable_dma(chip->dma2); | ||
| 1240 | free_dma(chip->dma2); | ||
| 1241 | } | ||
| 1242 | if (chip->irq >= 0) { | ||
| 1243 | free_irq(chip->irq, chip); | ||
| 1244 | } | ||
| 1245 | kfree(chip); | ||
| 1246 | return 0; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | static int snd_opti93x_dev_free(struct snd_device *device) | ||
| 1250 | { | ||
| 1251 | struct snd_opti93x *chip = device->device_data; | ||
| 1252 | return snd_opti93x_free(chip); | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | static const char *snd_opti93x_chip_id(struct snd_opti93x *codec) | ||
| 1256 | { | ||
| 1257 | switch (codec->hardware) { | ||
| 1258 | case OPTi9XX_HW_82C930: return "82C930"; | ||
| 1259 | case OPTi9XX_HW_82C931: return "82C931"; | ||
| 1260 | case OPTi9XX_HW_82C933: return "82C933"; | ||
| 1261 | default: return "???"; | ||
| 1262 | } | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | static int snd_opti93x_create(struct snd_card *card, struct snd_opti9xx *chip, | ||
| 1266 | int dma1, int dma2, | ||
| 1267 | struct snd_opti93x **rcodec) | ||
| 1268 | { | ||
| 1269 | static struct snd_device_ops ops = { | ||
| 1270 | .dev_free = snd_opti93x_dev_free, | ||
| 1271 | }; | ||
| 1272 | int error; | ||
| 1273 | struct snd_opti93x *codec; | ||
| 1274 | |||
| 1275 | *rcodec = NULL; | ||
| 1276 | codec = kzalloc(sizeof(*codec), GFP_KERNEL); | ||
| 1277 | if (codec == NULL) | ||
| 1278 | return -ENOMEM; | ||
| 1279 | codec->irq = -1; | ||
| 1280 | codec->dma1 = -1; | ||
| 1281 | codec->dma2 = -1; | ||
| 1282 | |||
| 1283 | if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) { | ||
| 1284 | snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4); | ||
| 1285 | snd_opti93x_free(codec); | ||
| 1286 | return -EBUSY; | ||
| 1287 | } | ||
| 1288 | if (request_dma(dma1, "OPTI93x - 1")) { | ||
| 1289 | snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1); | ||
| 1290 | snd_opti93x_free(codec); | ||
| 1291 | return -EBUSY; | ||
| 1292 | } | ||
| 1293 | codec->dma1 = chip->dma1; | ||
| 1294 | if (request_dma(dma2, "OPTI93x - 2")) { | ||
| 1295 | snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2); | ||
| 1296 | snd_opti93x_free(codec); | ||
| 1297 | return -EBUSY; | ||
| 1298 | } | ||
| 1299 | codec->dma2 = chip->dma2; | ||
| 1300 | |||
| 1301 | if (request_irq(chip->irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec)) { | ||
| 1302 | snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); | ||
| 1303 | snd_opti93x_free(codec); | ||
| 1304 | return -EBUSY; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | codec->card = card; | ||
| 1308 | codec->port = chip->wss_base + 4; | ||
| 1309 | codec->irq = chip->irq; | ||
| 1310 | |||
| 1311 | spin_lock_init(&codec->lock); | ||
| 1312 | codec->hardware = chip->hardware; | ||
| 1313 | codec->chip = chip; | ||
| 1314 | |||
| 1315 | if ((error = snd_opti93x_probe(codec))) { | ||
| 1316 | snd_opti93x_free(codec); | ||
| 1317 | return error; | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | snd_opti93x_init(codec); | ||
| 1321 | |||
| 1322 | /* Register device */ | ||
| 1323 | if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) { | ||
| 1324 | snd_opti93x_free(codec); | ||
| 1325 | return error; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | *rcodec = codec; | ||
| 1329 | return 0; | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | static struct snd_pcm_ops snd_opti93x_playback_ops = { | ||
| 1333 | .open = snd_opti93x_playback_open, | ||
| 1334 | .close = snd_opti93x_playback_close, | ||
| 1335 | .ioctl = snd_pcm_lib_ioctl, | ||
| 1336 | .hw_params = snd_opti93x_hw_params, | ||
| 1337 | .hw_free = snd_opti93x_hw_free, | ||
| 1338 | .prepare = snd_opti93x_playback_prepare, | ||
| 1339 | .trigger = snd_opti93x_playback_trigger, | ||
| 1340 | .pointer = snd_opti93x_playback_pointer, | ||
| 1341 | }; | ||
| 1342 | |||
| 1343 | static struct snd_pcm_ops snd_opti93x_capture_ops = { | ||
| 1344 | .open = snd_opti93x_capture_open, | ||
| 1345 | .close = snd_opti93x_capture_close, | ||
| 1346 | .ioctl = snd_pcm_lib_ioctl, | ||
| 1347 | .hw_params = snd_opti93x_hw_params, | ||
| 1348 | .hw_free = snd_opti93x_hw_free, | ||
| 1349 | .prepare = snd_opti93x_capture_prepare, | ||
| 1350 | .trigger = snd_opti93x_capture_trigger, | ||
| 1351 | .pointer = snd_opti93x_capture_pointer, | ||
| 1352 | }; | ||
| 1353 | |||
| 1354 | static int snd_opti93x_pcm(struct snd_opti93x *codec, int device, struct snd_pcm **rpcm) | ||
| 1355 | { | ||
| 1356 | int error; | ||
| 1357 | struct snd_pcm *pcm; | ||
| 1358 | |||
| 1359 | if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm)) < 0) | ||
| 1360 | return error; | ||
| 1361 | |||
| 1362 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops); | ||
| 1363 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops); | ||
| 1364 | |||
| 1365 | pcm->private_data = codec; | ||
| 1366 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; | ||
| 1367 | |||
| 1368 | strcpy(pcm->name, snd_opti93x_chip_id(codec)); | ||
| 1369 | |||
| 1370 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
| 1371 | snd_dma_isa_data(), | ||
| 1372 | 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024); | ||
| 1373 | |||
| 1374 | codec->pcm = pcm; | ||
| 1375 | if (rpcm) | ||
| 1376 | *rpcm = pcm; | ||
| 1377 | return 0; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | /* | ||
| 1381 | * MIXER part | ||
| 1382 | */ | ||
| 1383 | |||
| 1384 | static int snd_opti93x_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
| 1385 | { | ||
| 1386 | static char *texts[4] = { | ||
| 1387 | "Line1", "Aux", "Mic", "Mix" | ||
| 1388 | }; | ||
| 1389 | |||
| 1390 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 1391 | uinfo->count = 2; | ||
| 1392 | uinfo->value.enumerated.items = 4; | ||
| 1393 | if (uinfo->value.enumerated.item > 3) | ||
| 1394 | uinfo->value.enumerated.item = 3; | ||
| 1395 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
| 1396 | return 0; | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | static int snd_opti93x_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
| 1400 | { | ||
| 1401 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
| 1402 | unsigned long flags; | ||
| 1403 | |||
| 1404 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1405 | ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6; | ||
| 1406 | ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6; | ||
| 1407 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1408 | return 0; | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | static int snd_opti93x_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
| 1412 | { | ||
| 1413 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
| 1414 | unsigned long flags; | ||
| 1415 | unsigned short left, right; | ||
| 1416 | int change; | ||
| 1417 | |||
| 1418 | if (ucontrol->value.enumerated.item[0] > 3 || | ||
| 1419 | ucontrol->value.enumerated.item[1] > 3) | ||
| 1420 | return -EINVAL; | ||
| 1421 | left = ucontrol->value.enumerated.item[0] << 6; | ||
| 1422 | right = ucontrol->value.enumerated.item[1] << 6; | ||
| 1423 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1424 | left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left; | ||
| 1425 | right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right; | ||
| 1426 | change = left != chip->image[OPTi93X_MIXOUT_LEFT] || | ||
| 1427 | right != chip->image[OPTi93X_MIXOUT_RIGHT]; | ||
| 1428 | snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left); | ||
| 1429 | snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right); | ||
| 1430 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1431 | return change; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | #if 0 | ||
| 1435 | |||
| 1436 | #define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \ | ||
| 1437 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | ||
| 1438 | .info = snd_opti93x_info_single, \ | ||
| 1439 | .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \ | ||
| 1440 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } | ||
| 1441 | |||
| 1442 | static int snd_opti93x_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
| 1443 | { | ||
| 1444 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
| 1445 | |||
| 1446 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 1447 | uinfo->count = 1; | ||
| 1448 | uinfo->value.integer.min = 0; | ||
| 1449 | uinfo->value.integer.max = mask; | ||
| 1450 | return 0; | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | static int snd_opti93x_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
| 1454 | { | ||
| 1455 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
| 1456 | unsigned long flags; | ||
| 1457 | int reg = kcontrol->private_value & 0xff; | ||
| 1458 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
| 1459 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
| 1460 | int invert = (kcontrol->private_value >> 24) & 0xff; | ||
| 1461 | |||
| 1462 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1463 | ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; | ||
| 1464 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1465 | if (invert) | ||
| 1466 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
| 1467 | return 0; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | static int snd_opti93x_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
| 1471 | { | ||
| 1472 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
| 1473 | unsigned long flags; | ||
| 1474 | int reg = kcontrol->private_value & 0xff; | ||
| 1475 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
| 1476 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
| 1477 | int invert = (kcontrol->private_value >> 24) & 0xff; | ||
| 1478 | int change; | ||
| 1479 | unsigned short val; | ||
| 1480 | |||
| 1481 | val = (ucontrol->value.integer.value[0] & mask); | ||
| 1482 | if (invert) | ||
| 1483 | val = mask - val; | ||
| 1484 | val <<= shift; | ||
| 1485 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1486 | val = (chip->image[reg] & ~(mask << shift)) | val; | ||
| 1487 | change = val != chip->image[reg]; | ||
| 1488 | snd_opti93x_out(chip, reg, val); | ||
| 1489 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1490 | return change; | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | #endif /* single */ | ||
| 1494 | |||
| 1495 | #define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ | ||
| 1496 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | ||
| 1497 | .info = snd_opti93x_info_double, \ | ||
| 1498 | .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \ | ||
| 1499 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } | ||
| 1500 | |||
| 1501 | #define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \ | ||
| 1502 | do { xctl.private_value ^= 22; } while (0) | ||
| 1503 | #define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \ | ||
| 1504 | do { xctl.private_value &= ~0x0000ffff; \ | ||
| 1505 | xctl.private_value |= left_reg | (right_reg << 8); } while (0) | ||
| 1506 | |||
| 1507 | static int snd_opti93x_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
| 1508 | { | ||
| 1509 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
| 1510 | |||
| 1511 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 1512 | uinfo->count = 2; | ||
| 1513 | uinfo->value.integer.min = 0; | ||
| 1514 | uinfo->value.integer.max = mask; | ||
| 1515 | return 0; | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | static int snd_opti93x_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
| 1519 | { | ||
| 1520 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
| 1521 | unsigned long flags; | ||
| 1522 | int left_reg = kcontrol->private_value & 0xff; | ||
| 1523 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | ||
| 1524 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | ||
| 1525 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | ||
| 1526 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
| 1527 | int invert = (kcontrol->private_value >> 22) & 1; | ||
| 1528 | |||
| 1529 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1530 | ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; | ||
| 1531 | ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; | ||
| 1532 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1533 | if (invert) { | ||
| 1534 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
| 1535 | ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; | ||
| 1536 | } | ||
| 1537 | return 0; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | static int snd_opti93x_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
| 1541 | { | ||
| 1542 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
| 1543 | unsigned long flags; | ||
| 1544 | int left_reg = kcontrol->private_value & 0xff; | ||
| 1545 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | ||
| 1546 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | ||
| 1547 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | ||
| 1548 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
| 1549 | int invert = (kcontrol->private_value >> 22) & 1; | ||
| 1550 | int change; | ||
| 1551 | unsigned short val1, val2; | ||
| 1552 | |||
| 1553 | val1 = ucontrol->value.integer.value[0] & mask; | ||
| 1554 | val2 = ucontrol->value.integer.value[1] & mask; | ||
| 1555 | if (invert) { | ||
| 1556 | val1 = mask - val1; | ||
| 1557 | val2 = mask - val2; | ||
| 1558 | } | ||
| 1559 | val1 <<= shift_left; | ||
| 1560 | val2 <<= shift_right; | ||
| 1561 | spin_lock_irqsave(&chip->lock, flags); | ||
| 1562 | val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; | ||
| 1563 | val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; | ||
| 1564 | change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; | ||
| 1565 | snd_opti93x_out_image(chip, left_reg, val1); | ||
| 1566 | snd_opti93x_out_image(chip, right_reg, val2); | ||
| 1567 | spin_unlock_irqrestore(&chip->lock, flags); | ||
| 1568 | return change; | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | static struct snd_kcontrol_new snd_opti93x_controls[] __devinitdata = { | ||
| 1572 | OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
| 1573 | OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), | ||
| 1574 | OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1), | ||
| 1575 | OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1), | ||
| 1576 | OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1577 | OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1578 | OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1579 | OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1580 | OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1581 | OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1582 | OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1), | ||
| 1583 | OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1584 | OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1585 | OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 1586 | OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 1587 | OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0), | ||
| 1588 | { | ||
| 1589 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 1590 | .name = "Capture Source", | ||
| 1591 | .info = snd_opti93x_info_mux, | ||
| 1592 | .get = snd_opti93x_get_mux, | ||
| 1593 | .put = snd_opti93x_put_mux, | ||
| 1594 | } | ||
| 1595 | }; | ||
| 1596 | |||
| 1597 | static int __devinit snd_opti93x_mixer(struct snd_opti93x *chip) | ||
| 1598 | { | ||
| 1599 | struct snd_card *card; | ||
| 1600 | struct snd_kcontrol_new knew; | ||
| 1601 | int err; | ||
| 1602 | unsigned int idx; | ||
| 1603 | |||
| 1604 | snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); | ||
| 1605 | |||
| 1606 | card = chip->card; | ||
| 1607 | |||
| 1608 | strcpy(card->mixername, snd_opti93x_chip_id(chip)); | ||
| 1609 | |||
| 1610 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { | ||
| 1611 | knew = snd_opti93x_controls[idx]; | ||
| 1612 | if (chip->hardware == OPTi9XX_HW_82C930) { | ||
| 1613 | if (strstr(knew.name, "FM")) /* skip FM controls */ | ||
| 1614 | continue; | ||
| 1615 | else if (strcmp(knew.name, "Mic Playback Volume")) | ||
| 1616 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | ||
| 1617 | else if (strstr(knew.name, "Aux")) | ||
| 1618 | OPTi93X_DOUBLE_CHANGE_REGS(knew, OPTi930_AUX_LEFT_INPUT, OPTi930_AUX_RIGHT_INPUT); | ||
| 1619 | else if (strcmp(knew.name, "PCM Playback Volume")) | ||
| 1620 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | ||
| 1621 | else if (strcmp(knew.name, "Master Playback Volume")) | ||
| 1622 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | ||
| 1623 | } | ||
| 1624 | if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opti93x_controls[idx], chip))) < 0) | ||
| 1625 | return err; | ||
| 1626 | } | ||
| 1627 | return 0; | ||
| 1628 | } | ||
| 1629 | |||
| 1630 | #endif /* OPTi93X */ | 576 | #endif /* OPTi93X */ |
| 1631 | 577 | ||
| 1632 | static int __devinit snd_card_opti9xx_detect(struct snd_card *card, | 578 | static int __devinit snd_card_opti9xx_detect(struct snd_card *card, |
| @@ -1739,8 +685,16 @@ static void snd_card_opti9xx_free(struct snd_card *card) | |||
| 1739 | { | 685 | { |
| 1740 | struct snd_opti9xx *chip = card->private_data; | 686 | struct snd_opti9xx *chip = card->private_data; |
| 1741 | 687 | ||
| 1742 | if (chip) | 688 | if (chip) { |
| 689 | #ifdef OPTi93X | ||
| 690 | struct snd_cs4231 *codec = chip->codec; | ||
| 691 | if (codec->irq > 0) { | ||
| 692 | disable_irq(codec->irq); | ||
| 693 | free_irq(codec->irq, codec); | ||
| 694 | } | ||
| 695 | #endif | ||
| 1743 | release_and_free_resource(chip->res_mc_base); | 696 | release_and_free_resource(chip->res_mc_base); |
| 697 | } | ||
| 1744 | } | 698 | } |
| 1745 | 699 | ||
| 1746 | static int __devinit snd_opti9xx_probe(struct snd_card *card) | 700 | static int __devinit snd_opti9xx_probe(struct snd_card *card) |
| @@ -1748,11 +702,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) | |||
| 1748 | static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; | 702 | static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; |
| 1749 | int error; | 703 | int error; |
| 1750 | struct snd_opti9xx *chip = card->private_data; | 704 | struct snd_opti9xx *chip = card->private_data; |
| 1751 | #if defined(OPTi93X) | 705 | #if defined(CS4231) || defined(OPTi93X) |
| 1752 | struct snd_opti93x *codec; | ||
| 1753 | #elif defined(CS4231) | ||
| 1754 | struct snd_cs4231 *codec; | 706 | struct snd_cs4231 *codec; |
| 707 | #ifdef CS4231 | ||
| 1755 | struct snd_timer *timer; | 708 | struct snd_timer *timer; |
| 709 | #endif | ||
| 1756 | #else | 710 | #else |
| 1757 | struct snd_ad1848 *codec; | 711 | struct snd_ad1848 *codec; |
| 1758 | #endif | 712 | #endif |
| @@ -1784,26 +738,34 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) | |||
| 1784 | if ((error = snd_opti9xx_configure(chip))) | 738 | if ((error = snd_opti9xx_configure(chip))) |
| 1785 | return error; | 739 | return error; |
| 1786 | 740 | ||
| 1787 | #if defined(OPTi93X) | 741 | #if defined(CS4231) || defined(OPTi93X) |
| 1788 | if ((error = snd_opti93x_create(card, chip, chip->dma1, chip->dma2, &codec))) | ||
| 1789 | return error; | ||
| 1790 | if ((error = snd_opti93x_pcm(codec, 0, &pcm)) < 0) | ||
| 1791 | return error; | ||
| 1792 | if ((error = snd_opti93x_mixer(codec)) < 0) | ||
| 1793 | return error; | ||
| 1794 | #elif defined(CS4231) | ||
| 1795 | if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1, | 742 | if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1, |
| 1796 | chip->irq, chip->dma1, chip->dma2, | 743 | chip->irq, chip->dma1, chip->dma2, |
| 1797 | CS4231_HW_DETECT, | 744 | #ifdef CS4231 |
| 1798 | 0, | 745 | CS4231_HW_DETECT, 0, |
| 746 | #else /* OPTi93x */ | ||
| 747 | CS4231_HW_OPTI93X, CS4231_HWSHARE_IRQ, | ||
| 748 | #endif | ||
| 1799 | &codec)) < 0) | 749 | &codec)) < 0) |
| 1800 | return error; | 750 | return error; |
| 751 | #ifdef OPTi93X | ||
| 752 | chip->codec = codec; | ||
| 753 | #endif | ||
| 1801 | if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) | 754 | if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) |
| 1802 | return error; | 755 | return error; |
| 1803 | if ((error = snd_cs4231_mixer(codec)) < 0) | 756 | if ((error = snd_cs4231_mixer(codec)) < 0) |
| 1804 | return error; | 757 | return error; |
| 758 | #ifdef CS4231 | ||
| 1805 | if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) | 759 | if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) |
| 1806 | return error; | 760 | return error; |
| 761 | #else /* OPTI93X */ | ||
| 762 | error = request_irq(chip->irq, snd_opti93x_interrupt, | ||
| 763 | IRQF_DISABLED, DEV_NAME" - WSS", codec); | ||
| 764 | if (error < 0) { | ||
| 765 | snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); | ||
| 766 | return error; | ||
| 767 | } | ||
| 768 | #endif | ||
| 1807 | #else | 769 | #else |
| 1808 | if ((error = snd_ad1848_create(card, chip->wss_base + 4, | 770 | if ((error = snd_ad1848_create(card, chip->wss_base + 4, |
| 1809 | chip->irq, chip->dma1, | 771 | chip->irq, chip->dma1, |
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index c9d1c986d70e..1098a56b2f4b 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile | |||
| @@ -34,5 +34,3 @@ ifeq ($(CONFIG_SND_SB16_CSP),y) | |||
| 34 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o | 34 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o |
| 35 | endif | 35 | endif |
| 36 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o | 36 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o |
| 37 | |||
| 38 | obj-m := $(sort $(obj-m)) | ||
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 95eeca163354..0bb9b9256601 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c | |||
| @@ -1939,7 +1939,7 @@ static int __devinit | |||
| 1939 | wavefront_download_firmware (snd_wavefront_t *dev, char *path) | 1939 | wavefront_download_firmware (snd_wavefront_t *dev, char *path) |
| 1940 | 1940 | ||
| 1941 | { | 1941 | { |
| 1942 | unsigned char *buf; | 1942 | const unsigned char *buf; |
| 1943 | int len, err; | 1943 | int len, err; |
| 1944 | int section_cnt_downloaded = 0; | 1944 | int section_cnt_downloaded = 0; |
| 1945 | const struct firmware *firmware; | 1945 | const struct firmware *firmware; |
diff --git a/sound/mips/Kconfig b/sound/mips/Kconfig index 531f8ba96a71..a9823fad85c2 100644 --- a/sound/mips/Kconfig +++ b/sound/mips/Kconfig | |||
| @@ -1,15 +1,34 @@ | |||
| 1 | # ALSA MIPS drivers | 1 | # ALSA MIPS drivers |
| 2 | 2 | ||
| 3 | menu "ALSA MIPS devices" | 3 | menuconfig SND_MIPS |
| 4 | depends on SND!=n && MIPS | 4 | bool "MIPS sound devices" |
| 5 | depends on MIPS | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices of MIPS architectures. | ||
| 9 | |||
| 10 | if SND_MIPS | ||
| 11 | |||
| 12 | config SND_SGI_O2 | ||
| 13 | tristate "SGI O2 Audio" | ||
| 14 | depends on SGI_IP32 | ||
| 15 | help | ||
| 16 | Sound support for the SGI O2 Workstation. | ||
| 17 | |||
| 18 | config SND_SGI_HAL2 | ||
| 19 | tristate "SGI HAL2 Audio" | ||
| 20 | depends on SGI_HAS_HAL2 | ||
| 21 | help | ||
| 22 | Sound support for the SGI Indy and Indigo2 Workstation. | ||
| 23 | |||
| 5 | 24 | ||
| 6 | config SND_AU1X00 | 25 | config SND_AU1X00 |
| 7 | tristate "Au1x00 AC97 Port Driver" | 26 | tristate "Au1x00 AC97 Port Driver" |
| 8 | depends on (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SND | 27 | depends on SOC_AU1000 || SOC_AU1100 || SOC_AU1500 |
| 9 | select SND_PCM | 28 | select SND_PCM |
| 10 | select SND_AC97_CODEC | 29 | select SND_AC97_CODEC |
| 11 | help | 30 | help |
| 12 | ALSA Sound driver for the Au1x00's AC97 port. | 31 | ALSA Sound driver for the Au1x00's AC97 port. |
| 13 | 32 | ||
| 14 | endmenu | 33 | endif # SND_MIPS |
| 15 | 34 | ||
diff --git a/sound/mips/Makefile b/sound/mips/Makefile index 47afed971fba..861ec0a574b4 100644 --- a/sound/mips/Makefile +++ b/sound/mips/Makefile | |||
| @@ -3,6 +3,10 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | snd-au1x00-objs := au1x00.o | 5 | snd-au1x00-objs := au1x00.o |
| 6 | snd-sgi-o2-objs := sgio2audio.o ad1843.o | ||
| 7 | snd-sgi-hal2-objs := hal2.o | ||
| 6 | 8 | ||
| 7 | # Toplevel Module Dependency | 9 | # Toplevel Module Dependency |
| 8 | obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o | 10 | obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o |
| 11 | obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o | ||
| 12 | obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o | ||
diff --git a/sound/mips/ad1843.c b/sound/mips/ad1843.c new file mode 100644 index 000000000000..c624510ec374 --- /dev/null +++ b/sound/mips/ad1843.c | |||
| @@ -0,0 +1,561 @@ | |||
| 1 | /* | ||
| 2 | * AD1843 low level driver | ||
| 3 | * | ||
| 4 | * Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org> | ||
| 5 | * Copyright 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de> | ||
| 6 | * | ||
| 7 | * inspired from vwsnd.c (SGI VW audio driver) | ||
| 8 | * Copyright 1999 Silicon Graphics, Inc. All rights reserved. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program; if not, write to the Free Software | ||
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/sched.h> | ||
| 28 | #include <linux/errno.h> | ||
| 29 | #include <sound/core.h> | ||
| 30 | #include <sound/pcm.h> | ||
| 31 | #include <sound/ad1843.h> | ||
| 32 | |||
| 33 | /* | ||
| 34 | * AD1843 bitfield definitions. All are named as in the AD1843 data | ||
| 35 | * sheet, with ad1843_ prepended and individual bit numbers removed. | ||
| 36 | * | ||
| 37 | * E.g., bits LSS0 through LSS2 become ad1843_LSS. | ||
| 38 | * | ||
| 39 | * Only the bitfields we need are defined. | ||
| 40 | */ | ||
| 41 | |||
| 42 | struct ad1843_bitfield { | ||
| 43 | char reg; | ||
| 44 | char lo_bit; | ||
| 45 | char nbits; | ||
| 46 | }; | ||
| 47 | |||
| 48 | static const struct ad1843_bitfield | ||
| 49 | ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */ | ||
| 50 | ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */ | ||
| 51 | ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */ | ||
| 52 | ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */ | ||
| 53 | ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */ | ||
| 54 | ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */ | ||
| 55 | ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */ | ||
| 56 | ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */ | ||
| 57 | ad1843_RD2M = { 3, 0, 5 }, /* Right DAC 2 Mix Gain/Atten */ | ||
| 58 | ad1843_RD2MM = { 3, 7, 1 }, /* Right DAC 2 Mix Mute */ | ||
| 59 | ad1843_LD2M = { 3, 8, 5 }, /* Left DAC 2 Mix Gain/Atten */ | ||
| 60 | ad1843_LD2MM = { 3, 15, 1 }, /* Left DAC 2 Mix Mute */ | ||
| 61 | ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */ | ||
| 62 | ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */ | ||
| 63 | ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */ | ||
| 64 | ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */ | ||
| 65 | ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */ | ||
| 66 | ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */ | ||
| 67 | ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */ | ||
| 68 | ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */ | ||
| 69 | ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */ | ||
| 70 | ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */ | ||
| 71 | ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */ | ||
| 72 | ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */ | ||
| 73 | ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */ | ||
| 74 | ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */ | ||
| 75 | ad1843_MPOM = { 8, 6, 1 }, /* Mono Output Mute */ | ||
| 76 | ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */ | ||
| 77 | ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */ | ||
| 78 | ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */ | ||
| 79 | ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */ | ||
| 80 | ad1843_RDA2G = { 10, 0, 6 }, /* Right DAC2 Analog/Digital Gain */ | ||
| 81 | ad1843_RDA2GM = { 10, 7, 1 }, /* Right DAC2 Analog Mute */ | ||
| 82 | ad1843_LDA2G = { 10, 8, 6 }, /* Left DAC2 Analog/Digital Gain */ | ||
| 83 | ad1843_LDA2GM = { 10, 15, 1 }, /* Left DAC2 Analog Mute */ | ||
| 84 | ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */ | ||
| 85 | ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */ | ||
| 86 | ad1843_RDA2AM = { 12, 7, 1 }, /* Right DAC2 Digital Mute */ | ||
| 87 | ad1843_LDA2AM = { 12, 15, 1 }, /* Left DAC2 Digital Mute */ | ||
| 88 | ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */ | ||
| 89 | ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */ | ||
| 90 | ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */ | ||
| 91 | ad1843_DA2C = { 15, 10, 2 }, /* DAC2 Sample Rate Source */ | ||
| 92 | ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */ | ||
| 93 | ad1843_C2C = { 20, 0, 16 }, /* Clock 2 Sample Rate Select */ | ||
| 94 | ad1843_C3C = { 23, 0, 16 }, /* Clock 3 Sample Rate Select */ | ||
| 95 | ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */ | ||
| 96 | ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */ | ||
| 97 | ad1843_DAMIX = { 25, 14, 1 }, /* DAC Digital Mix Enable */ | ||
| 98 | ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */ | ||
| 99 | ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */ | ||
| 100 | ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */ | ||
| 101 | ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */ | ||
| 102 | ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */ | ||
| 103 | ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */ | ||
| 104 | ad1843_DA2F = { 26, 10, 2 }, /* DAC2 Data Format Select */ | ||
| 105 | ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */ | ||
| 106 | ad1843_DA2SM = { 26, 15, 1 }, /* DAC2 Stereo/Mono Mode Select */ | ||
| 107 | ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */ | ||
| 108 | ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */ | ||
| 109 | ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */ | ||
| 110 | ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */ | ||
| 111 | ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */ | ||
| 112 | ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */ | ||
| 113 | ad1843_DDMEN = { 27, 12, 1 }, /* DAC2 to DAC1 Mix Enable */ | ||
| 114 | ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */ | ||
| 115 | ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */ | ||
| 116 | ad1843_C3EN = { 28, 13, 1 }, /* Clock Generator 3 Enable */ | ||
| 117 | ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */ | ||
| 118 | |||
| 119 | /* | ||
| 120 | * The various registers of the AD1843 use three different formats for | ||
| 121 | * specifying gain. The ad1843_gain structure parameterizes the | ||
| 122 | * formats. | ||
| 123 | */ | ||
| 124 | |||
| 125 | struct ad1843_gain { | ||
| 126 | int negative; /* nonzero if gain is negative. */ | ||
| 127 | const struct ad1843_bitfield *lfield; | ||
| 128 | const struct ad1843_bitfield *rfield; | ||
| 129 | const struct ad1843_bitfield *lmute; | ||
| 130 | const struct ad1843_bitfield *rmute; | ||
| 131 | }; | ||
| 132 | |||
| 133 | static const struct ad1843_gain ad1843_gain_RECLEV = { | ||
| 134 | .negative = 0, | ||
| 135 | .lfield = &ad1843_LIG, | ||
| 136 | .rfield = &ad1843_RIG | ||
| 137 | }; | ||
| 138 | static const struct ad1843_gain ad1843_gain_LINE = { | ||
| 139 | .negative = 1, | ||
| 140 | .lfield = &ad1843_LX1M, | ||
| 141 | .rfield = &ad1843_RX1M, | ||
| 142 | .lmute = &ad1843_LX1MM, | ||
| 143 | .rmute = &ad1843_RX1MM | ||
| 144 | }; | ||
| 145 | static const struct ad1843_gain ad1843_gain_LINE_2 = { | ||
| 146 | .negative = 1, | ||
| 147 | .lfield = &ad1843_LDA2G, | ||
| 148 | .rfield = &ad1843_RDA2G, | ||
| 149 | .lmute = &ad1843_LDA2GM, | ||
| 150 | .rmute = &ad1843_RDA2GM | ||
| 151 | }; | ||
| 152 | static const struct ad1843_gain ad1843_gain_MIC = { | ||
| 153 | .negative = 1, | ||
| 154 | .lfield = &ad1843_LMCM, | ||
| 155 | .rfield = &ad1843_RMCM, | ||
| 156 | .lmute = &ad1843_LMCMM, | ||
| 157 | .rmute = &ad1843_RMCMM | ||
| 158 | }; | ||
| 159 | static const struct ad1843_gain ad1843_gain_PCM_0 = { | ||
| 160 | .negative = 1, | ||
| 161 | .lfield = &ad1843_LDA1G, | ||
| 162 | .rfield = &ad1843_RDA1G, | ||
| 163 | .lmute = &ad1843_LDA1GM, | ||
| 164 | .rmute = &ad1843_RDA1GM | ||
| 165 | }; | ||
| 166 | static const struct ad1843_gain ad1843_gain_PCM_1 = { | ||
| 167 | .negative = 1, | ||
| 168 | .lfield = &ad1843_LD2M, | ||
| 169 | .rfield = &ad1843_RD2M, | ||
| 170 | .lmute = &ad1843_LD2MM, | ||
| 171 | .rmute = &ad1843_RD2MM | ||
| 172 | }; | ||
| 173 | |||
| 174 | static const struct ad1843_gain *ad1843_gain[AD1843_GAIN_SIZE] = | ||
| 175 | { | ||
| 176 | &ad1843_gain_RECLEV, | ||
| 177 | &ad1843_gain_LINE, | ||
| 178 | &ad1843_gain_LINE_2, | ||
| 179 | &ad1843_gain_MIC, | ||
| 180 | &ad1843_gain_PCM_0, | ||
| 181 | &ad1843_gain_PCM_1, | ||
| 182 | }; | ||
| 183 | |||
| 184 | /* read the current value of an AD1843 bitfield. */ | ||
| 185 | |||
| 186 | static int ad1843_read_bits(struct snd_ad1843 *ad1843, | ||
| 187 | const struct ad1843_bitfield *field) | ||
| 188 | { | ||
| 189 | int w; | ||
| 190 | |||
| 191 | w = ad1843->read(ad1843->chip, field->reg); | ||
| 192 | return w >> field->lo_bit & ((1 << field->nbits) - 1); | ||
| 193 | } | ||
| 194 | |||
| 195 | /* | ||
| 196 | * write a new value to an AD1843 bitfield and return the old value. | ||
| 197 | */ | ||
| 198 | |||
| 199 | static int ad1843_write_bits(struct snd_ad1843 *ad1843, | ||
| 200 | const struct ad1843_bitfield *field, | ||
| 201 | int newval) | ||
| 202 | { | ||
| 203 | int w, mask, oldval, newbits; | ||
| 204 | |||
| 205 | w = ad1843->read(ad1843->chip, field->reg); | ||
| 206 | mask = ((1 << field->nbits) - 1) << field->lo_bit; | ||
| 207 | oldval = (w & mask) >> field->lo_bit; | ||
| 208 | newbits = (newval << field->lo_bit) & mask; | ||
| 209 | w = (w & ~mask) | newbits; | ||
| 210 | ad1843->write(ad1843->chip, field->reg, w); | ||
| 211 | |||
| 212 | return oldval; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | ||
| 216 | * ad1843_read_multi reads multiple bitfields from the same AD1843 | ||
| 217 | * register. It uses a single read cycle to do it. (Reading the | ||
| 218 | * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 | ||
| 219 | * microseconds.) | ||
| 220 | * | ||
| 221 | * Called like this. | ||
| 222 | * | ||
| 223 | * ad1843_read_multi(ad1843, nfields, | ||
| 224 | * &ad1843_FIELD1, &val1, | ||
| 225 | * &ad1843_FIELD2, &val2, ...); | ||
| 226 | */ | ||
| 227 | |||
| 228 | static void ad1843_read_multi(struct snd_ad1843 *ad1843, int argcount, ...) | ||
| 229 | { | ||
| 230 | va_list ap; | ||
| 231 | const struct ad1843_bitfield *fp; | ||
| 232 | int w = 0, mask, *value, reg = -1; | ||
| 233 | |||
| 234 | va_start(ap, argcount); | ||
| 235 | while (--argcount >= 0) { | ||
| 236 | fp = va_arg(ap, const struct ad1843_bitfield *); | ||
| 237 | value = va_arg(ap, int *); | ||
| 238 | if (reg == -1) { | ||
| 239 | reg = fp->reg; | ||
| 240 | w = ad1843->read(ad1843->chip, reg); | ||
| 241 | } | ||
| 242 | |||
| 243 | mask = (1 << fp->nbits) - 1; | ||
| 244 | *value = w >> fp->lo_bit & mask; | ||
| 245 | } | ||
| 246 | va_end(ap); | ||
| 247 | } | ||
| 248 | |||
| 249 | /* | ||
| 250 | * ad1843_write_multi stores multiple bitfields into the same AD1843 | ||
| 251 | * register. It uses one read and one write cycle to do it. | ||
| 252 | * | ||
| 253 | * Called like this. | ||
| 254 | * | ||
| 255 | * ad1843_write_multi(ad1843, nfields, | ||
| 256 | * &ad1843_FIELD1, val1, | ||
| 257 | * &ad1843_FIELF2, val2, ...); | ||
| 258 | */ | ||
| 259 | |||
| 260 | static void ad1843_write_multi(struct snd_ad1843 *ad1843, int argcount, ...) | ||
| 261 | { | ||
| 262 | va_list ap; | ||
| 263 | int reg; | ||
| 264 | const struct ad1843_bitfield *fp; | ||
| 265 | int value; | ||
| 266 | int w, m, mask, bits; | ||
| 267 | |||
| 268 | mask = 0; | ||
| 269 | bits = 0; | ||
| 270 | reg = -1; | ||
| 271 | |||
| 272 | va_start(ap, argcount); | ||
| 273 | while (--argcount >= 0) { | ||
| 274 | fp = va_arg(ap, const struct ad1843_bitfield *); | ||
| 275 | value = va_arg(ap, int); | ||
| 276 | if (reg == -1) | ||
| 277 | reg = fp->reg; | ||
| 278 | else | ||
| 279 | BUG_ON(reg != fp->reg); | ||
| 280 | m = ((1 << fp->nbits) - 1) << fp->lo_bit; | ||
| 281 | mask |= m; | ||
| 282 | bits |= (value << fp->lo_bit) & m; | ||
| 283 | } | ||
| 284 | va_end(ap); | ||
| 285 | |||
| 286 | if (~mask & 0xFFFF) | ||
| 287 | w = ad1843->read(ad1843->chip, reg); | ||
| 288 | else | ||
| 289 | w = 0; | ||
| 290 | w = (w & ~mask) | bits; | ||
| 291 | ad1843->write(ad1843->chip, reg, w); | ||
| 292 | } | ||
| 293 | |||
| 294 | int ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id) | ||
| 295 | { | ||
| 296 | const struct ad1843_gain *gp = ad1843_gain[id]; | ||
| 297 | int ret; | ||
| 298 | |||
| 299 | ret = (1 << gp->lfield->nbits); | ||
| 300 | if (!gp->lmute) | ||
| 301 | ret -= 1; | ||
| 302 | return ret; | ||
| 303 | } | ||
| 304 | |||
| 305 | /* | ||
| 306 | * ad1843_get_gain reads the specified register and extracts the gain value | ||
| 307 | * using the supplied gain type. | ||
| 308 | */ | ||
| 309 | |||
| 310 | int ad1843_get_gain(struct snd_ad1843 *ad1843, int id) | ||
| 311 | { | ||
| 312 | int lg, rg, lm, rm; | ||
| 313 | const struct ad1843_gain *gp = ad1843_gain[id]; | ||
| 314 | unsigned short mask = (1 << gp->lfield->nbits) - 1; | ||
| 315 | |||
| 316 | ad1843_read_multi(ad1843, 2, gp->lfield, &lg, gp->rfield, &rg); | ||
| 317 | if (gp->negative) { | ||
| 318 | lg = mask - lg; | ||
| 319 | rg = mask - rg; | ||
| 320 | } | ||
| 321 | if (gp->lmute) { | ||
| 322 | ad1843_read_multi(ad1843, 2, gp->lmute, &lm, gp->rmute, &rm); | ||
| 323 | if (lm) | ||
| 324 | lg = 0; | ||
| 325 | if (rm) | ||
| 326 | rg = 0; | ||
| 327 | } | ||
| 328 | return lg << 0 | rg << 8; | ||
| 329 | } | ||
| 330 | |||
| 331 | /* | ||
| 332 | * Set an audio channel's gain. | ||
| 333 | * | ||
| 334 | * Returns the new gain, which may be lower than the old gain. | ||
| 335 | */ | ||
| 336 | |||
| 337 | int ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval) | ||
| 338 | { | ||
| 339 | const struct ad1843_gain *gp = ad1843_gain[id]; | ||
| 340 | unsigned short mask = (1 << gp->lfield->nbits) - 1; | ||
| 341 | |||
| 342 | int lg = (newval >> 0) & mask; | ||
| 343 | int rg = (newval >> 8) & mask; | ||
| 344 | int lm = (lg == 0) ? 1 : 0; | ||
| 345 | int rm = (rg == 0) ? 1 : 0; | ||
| 346 | |||
| 347 | if (gp->negative) { | ||
| 348 | lg = mask - lg; | ||
| 349 | rg = mask - rg; | ||
| 350 | } | ||
| 351 | if (gp->lmute) | ||
| 352 | ad1843_write_multi(ad1843, 2, gp->lmute, lm, gp->rmute, rm); | ||
| 353 | ad1843_write_multi(ad1843, 2, gp->lfield, lg, gp->rfield, rg); | ||
| 354 | return ad1843_get_gain(ad1843, id); | ||
| 355 | } | ||
| 356 | |||
| 357 | /* Returns the current recording source */ | ||
| 358 | |||
| 359 | int ad1843_get_recsrc(struct snd_ad1843 *ad1843) | ||
| 360 | { | ||
| 361 | int val = ad1843_read_bits(ad1843, &ad1843_LSS); | ||
| 362 | |||
| 363 | if (val < 0 || val > 2) { | ||
| 364 | val = 2; | ||
| 365 | ad1843_write_multi(ad1843, 2, | ||
| 366 | &ad1843_LSS, val, &ad1843_RSS, val); | ||
| 367 | } | ||
| 368 | return val; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* | ||
| 372 | * Set recording source. | ||
| 373 | * | ||
| 374 | * Returns newsrc on success, -errno on failure. | ||
| 375 | */ | ||
| 376 | |||
| 377 | int ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc) | ||
| 378 | { | ||
| 379 | if (newsrc < 0 || newsrc > 2) | ||
| 380 | return -EINVAL; | ||
| 381 | |||
| 382 | ad1843_write_multi(ad1843, 2, &ad1843_LSS, newsrc, &ad1843_RSS, newsrc); | ||
| 383 | return newsrc; | ||
| 384 | } | ||
| 385 | |||
| 386 | /* Setup ad1843 for D/A conversion. */ | ||
| 387 | |||
| 388 | void ad1843_setup_dac(struct snd_ad1843 *ad1843, | ||
| 389 | unsigned int id, | ||
| 390 | unsigned int framerate, | ||
| 391 | snd_pcm_format_t fmt, | ||
| 392 | unsigned int channels) | ||
| 393 | { | ||
| 394 | int ad_fmt = 0, ad_mode = 0; | ||
| 395 | |||
| 396 | switch (fmt) { | ||
| 397 | case SNDRV_PCM_FORMAT_S8: | ||
| 398 | ad_fmt = 0; | ||
| 399 | break; | ||
| 400 | case SNDRV_PCM_FORMAT_U8: | ||
| 401 | ad_fmt = 0; | ||
| 402 | break; | ||
| 403 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 404 | ad_fmt = 1; | ||
| 405 | break; | ||
| 406 | case SNDRV_PCM_FORMAT_MU_LAW: | ||
| 407 | ad_fmt = 2; | ||
| 408 | break; | ||
| 409 | case SNDRV_PCM_FORMAT_A_LAW: | ||
| 410 | ad_fmt = 3; | ||
| 411 | break; | ||
| 412 | default: | ||
| 413 | break; | ||
| 414 | } | ||
| 415 | |||
| 416 | switch (channels) { | ||
| 417 | case 2: | ||
| 418 | ad_mode = 0; | ||
| 419 | break; | ||
| 420 | case 1: | ||
| 421 | ad_mode = 1; | ||
| 422 | break; | ||
| 423 | default: | ||
| 424 | break; | ||
| 425 | } | ||
| 426 | |||
| 427 | if (id) { | ||
| 428 | ad1843_write_bits(ad1843, &ad1843_C2C, framerate); | ||
| 429 | ad1843_write_multi(ad1843, 2, | ||
| 430 | &ad1843_DA2SM, ad_mode, | ||
| 431 | &ad1843_DA2F, ad_fmt); | ||
| 432 | } else { | ||
| 433 | ad1843_write_bits(ad1843, &ad1843_C1C, framerate); | ||
| 434 | ad1843_write_multi(ad1843, 2, | ||
| 435 | &ad1843_DA1SM, ad_mode, | ||
| 436 | &ad1843_DA1F, ad_fmt); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | void ad1843_shutdown_dac(struct snd_ad1843 *ad1843, unsigned int id) | ||
| 441 | { | ||
| 442 | if (id) | ||
| 443 | ad1843_write_bits(ad1843, &ad1843_DA2F, 1); | ||
| 444 | else | ||
| 445 | ad1843_write_bits(ad1843, &ad1843_DA1F, 1); | ||
| 446 | } | ||
| 447 | |||
| 448 | void ad1843_setup_adc(struct snd_ad1843 *ad1843, | ||
| 449 | unsigned int framerate, | ||
| 450 | snd_pcm_format_t fmt, | ||
| 451 | unsigned int channels) | ||
| 452 | { | ||
| 453 | int da_fmt = 0; | ||
| 454 | |||
| 455 | switch (fmt) { | ||
| 456 | case SNDRV_PCM_FORMAT_S8: da_fmt = 0; break; | ||
| 457 | case SNDRV_PCM_FORMAT_U8: da_fmt = 0; break; | ||
| 458 | case SNDRV_PCM_FORMAT_S16_LE: da_fmt = 1; break; | ||
| 459 | case SNDRV_PCM_FORMAT_MU_LAW: da_fmt = 2; break; | ||
| 460 | case SNDRV_PCM_FORMAT_A_LAW: da_fmt = 3; break; | ||
| 461 | default: break; | ||
| 462 | } | ||
| 463 | |||
| 464 | ad1843_write_bits(ad1843, &ad1843_C3C, framerate); | ||
| 465 | ad1843_write_multi(ad1843, 2, | ||
| 466 | &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt); | ||
| 467 | } | ||
| 468 | |||
| 469 | void ad1843_shutdown_adc(struct snd_ad1843 *ad1843) | ||
| 470 | { | ||
| 471 | /* nothing to do */ | ||
| 472 | } | ||
| 473 | |||
| 474 | /* | ||
| 475 | * Fully initialize the ad1843. As described in the AD1843 data | ||
| 476 | * sheet, section "START-UP SEQUENCE". The numbered comments are | ||
| 477 | * subsection headings from the data sheet. See the data sheet, pages | ||
| 478 | * 52-54, for more info. | ||
| 479 | * | ||
| 480 | * return 0 on success, -errno on failure. */ | ||
| 481 | |||
| 482 | int ad1843_init(struct snd_ad1843 *ad1843) | ||
| 483 | { | ||
| 484 | unsigned long later; | ||
| 485 | |||
| 486 | if (ad1843_read_bits(ad1843, &ad1843_INIT) != 0) { | ||
| 487 | printk(KERN_ERR "ad1843: AD1843 won't initialize\n"); | ||
| 488 | return -EIO; | ||
| 489 | } | ||
| 490 | |||
| 491 | ad1843_write_bits(ad1843, &ad1843_SCF, 1); | ||
| 492 | |||
| 493 | /* 4. Put the conversion resources into standby. */ | ||
| 494 | ad1843_write_bits(ad1843, &ad1843_PDNI, 0); | ||
| 495 | later = jiffies + msecs_to_jiffies(500); | ||
| 496 | |||
| 497 | while (ad1843_read_bits(ad1843, &ad1843_PDNO)) { | ||
| 498 | if (time_after(jiffies, later)) { | ||
| 499 | printk(KERN_ERR | ||
| 500 | "ad1843: AD1843 won't power up\n"); | ||
| 501 | return -EIO; | ||
| 502 | } | ||
| 503 | schedule_timeout_interruptible(5); | ||
| 504 | } | ||
| 505 | |||
| 506 | /* 5. Power up the clock generators and enable clock output pins. */ | ||
| 507 | ad1843_write_multi(ad1843, 3, | ||
| 508 | &ad1843_C1EN, 1, | ||
| 509 | &ad1843_C2EN, 1, | ||
| 510 | &ad1843_C3EN, 1); | ||
| 511 | |||
| 512 | /* 6. Configure conversion resources while they are in standby. */ | ||
| 513 | |||
| 514 | /* DAC1/2 use clock 1/2 as source, ADC uses clock 3. Always. */ | ||
| 515 | ad1843_write_multi(ad1843, 4, | ||
| 516 | &ad1843_DA1C, 1, | ||
| 517 | &ad1843_DA2C, 2, | ||
| 518 | &ad1843_ADLC, 3, | ||
| 519 | &ad1843_ADRC, 3); | ||
| 520 | |||
| 521 | /* 7. Enable conversion resources. */ | ||
| 522 | ad1843_write_bits(ad1843, &ad1843_ADTLK, 1); | ||
| 523 | ad1843_write_multi(ad1843, 7, | ||
| 524 | &ad1843_ANAEN, 1, | ||
| 525 | &ad1843_AAMEN, 1, | ||
| 526 | &ad1843_DA1EN, 1, | ||
| 527 | &ad1843_DA2EN, 1, | ||
| 528 | &ad1843_DDMEN, 1, | ||
| 529 | &ad1843_ADLEN, 1, | ||
| 530 | &ad1843_ADREN, 1); | ||
| 531 | |||
| 532 | /* 8. Configure conversion resources while they are enabled. */ | ||
| 533 | |||
| 534 | /* set gain to 0 for all channels */ | ||
| 535 | ad1843_set_gain(ad1843, AD1843_GAIN_RECLEV, 0); | ||
| 536 | ad1843_set_gain(ad1843, AD1843_GAIN_LINE, 0); | ||
| 537 | ad1843_set_gain(ad1843, AD1843_GAIN_LINE_2, 0); | ||
| 538 | ad1843_set_gain(ad1843, AD1843_GAIN_MIC, 0); | ||
| 539 | ad1843_set_gain(ad1843, AD1843_GAIN_PCM_0, 0); | ||
| 540 | ad1843_set_gain(ad1843, AD1843_GAIN_PCM_1, 0); | ||
| 541 | |||
| 542 | /* Unmute all channels. */ | ||
| 543 | /* DAC1 */ | ||
| 544 | ad1843_write_multi(ad1843, 2, &ad1843_LDA1GM, 0, &ad1843_RDA1GM, 0); | ||
| 545 | /* DAC2 */ | ||
| 546 | ad1843_write_multi(ad1843, 2, &ad1843_LDA2GM, 0, &ad1843_RDA2GM, 0); | ||
| 547 | |||
| 548 | /* Set default recording source to Line In and set | ||
| 549 | * mic gain to +20 dB. | ||
| 550 | */ | ||
| 551 | ad1843_set_recsrc(ad1843, 2); | ||
| 552 | ad1843_write_multi(ad1843, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1); | ||
| 553 | |||
| 554 | /* Set Speaker Out level to +/- 4V and unmute it. */ | ||
| 555 | ad1843_write_multi(ad1843, 3, | ||
| 556 | &ad1843_HPOS, 1, | ||
| 557 | &ad1843_HPOM, 0, | ||
| 558 | &ad1843_MPOM, 0); | ||
| 559 | |||
| 560 | return 0; | ||
| 561 | } | ||
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c new file mode 100644 index 000000000000..db495be01861 --- /dev/null +++ b/sound/mips/hal2.c | |||
| @@ -0,0 +1,947 @@ | |||
| 1 | /* | ||
| 2 | * Driver for A2 audio system used in SGI machines | ||
| 3 | * Copyright (c) 2008 Thomas Bogendoerfer <tsbogend@alpha.fanken.de> | ||
| 4 | * | ||
| 5 | * Based on OSS code from Ladislav Michl <ladis@linux-mips.org>, which | ||
| 6 | * was based on code from Ulf Carlsson | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/dma-mapping.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/io.h> | ||
| 28 | |||
| 29 | #include <asm/sgi/hpc3.h> | ||
| 30 | #include <asm/sgi/ip22.h> | ||
| 31 | |||
| 32 | #include <sound/core.h> | ||
| 33 | #include <sound/control.h> | ||
| 34 | #include <sound/pcm.h> | ||
| 35 | #include <sound/pcm-indirect.h> | ||
| 36 | #include <sound/initval.h> | ||
| 37 | |||
| 38 | #include "hal2.h" | ||
| 39 | |||
| 40 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | ||
| 41 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | ||
| 42 | |||
| 43 | module_param(index, int, 0444); | ||
| 44 | MODULE_PARM_DESC(index, "Index value for SGI HAL2 soundcard."); | ||
| 45 | module_param(id, charp, 0444); | ||
| 46 | MODULE_PARM_DESC(id, "ID string for SGI HAL2 soundcard."); | ||
| 47 | MODULE_DESCRIPTION("ALSA driver for SGI HAL2 audio"); | ||
| 48 | MODULE_AUTHOR("Thomas Bogendoerfer"); | ||
| 49 | MODULE_LICENSE("GPL"); | ||
| 50 | |||
| 51 | |||
| 52 | #define H2_BLOCK_SIZE 1024 | ||
| 53 | #define H2_BUF_SIZE 16384 | ||
| 54 | |||
| 55 | struct hal2_pbus { | ||
| 56 | struct hpc3_pbus_dmacregs *pbus; | ||
| 57 | int pbusnr; | ||
| 58 | unsigned int ctrl; /* Current state of pbus->pbdma_ctrl */ | ||
| 59 | }; | ||
| 60 | |||
| 61 | struct hal2_desc { | ||
| 62 | struct hpc_dma_desc desc; | ||
| 63 | u32 pad; /* padding */ | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct hal2_codec { | ||
| 67 | struct snd_pcm_indirect pcm_indirect; | ||
| 68 | struct snd_pcm_substream *substream; | ||
| 69 | |||
| 70 | unsigned char *buffer; | ||
| 71 | dma_addr_t buffer_dma; | ||
| 72 | struct hal2_desc *desc; | ||
| 73 | dma_addr_t desc_dma; | ||
| 74 | int desc_count; | ||
| 75 | struct hal2_pbus pbus; | ||
| 76 | int voices; /* mono/stereo */ | ||
| 77 | unsigned int sample_rate; | ||
| 78 | unsigned int master; /* Master frequency */ | ||
| 79 | unsigned short mod; /* MOD value */ | ||
| 80 | unsigned short inc; /* INC value */ | ||
| 81 | }; | ||
| 82 | |||
| 83 | #define H2_MIX_OUTPUT_ATT 0 | ||
| 84 | #define H2_MIX_INPUT_GAIN 1 | ||
| 85 | |||
| 86 | struct snd_hal2 { | ||
| 87 | struct snd_card *card; | ||
| 88 | |||
| 89 | struct hal2_ctl_regs *ctl_regs; /* HAL2 ctl registers */ | ||
| 90 | struct hal2_aes_regs *aes_regs; /* HAL2 aes registers */ | ||
| 91 | struct hal2_vol_regs *vol_regs; /* HAL2 vol registers */ | ||
| 92 | struct hal2_syn_regs *syn_regs; /* HAL2 syn registers */ | ||
| 93 | |||
| 94 | struct hal2_codec dac; | ||
| 95 | struct hal2_codec adc; | ||
| 96 | }; | ||
| 97 | |||
| 98 | #define H2_INDIRECT_WAIT(regs) while (hal2_read(®s->isr) & H2_ISR_TSTATUS); | ||
| 99 | |||
| 100 | #define H2_READ_ADDR(addr) (addr | (1<<7)) | ||
| 101 | #define H2_WRITE_ADDR(addr) (addr) | ||
| 102 | |||
| 103 | static inline u32 hal2_read(u32 *reg) | ||
| 104 | { | ||
| 105 | return __raw_readl(reg); | ||
| 106 | } | ||
| 107 | |||
| 108 | static inline void hal2_write(u32 val, u32 *reg) | ||
| 109 | { | ||
| 110 | __raw_writel(val, reg); | ||
| 111 | } | ||
| 112 | |||
| 113 | |||
| 114 | static u32 hal2_i_read32(struct snd_hal2 *hal2, u16 addr) | ||
| 115 | { | ||
| 116 | u32 ret; | ||
| 117 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
| 118 | |||
| 119 | hal2_write(H2_READ_ADDR(addr), ®s->iar); | ||
| 120 | H2_INDIRECT_WAIT(regs); | ||
| 121 | ret = hal2_read(®s->idr0) & 0xffff; | ||
| 122 | hal2_write(H2_READ_ADDR(addr) | 0x1, ®s->iar); | ||
| 123 | H2_INDIRECT_WAIT(regs); | ||
| 124 | ret |= (hal2_read(®s->idr0) & 0xffff) << 16; | ||
| 125 | return ret; | ||
| 126 | } | ||
| 127 | |||
| 128 | static void hal2_i_write16(struct snd_hal2 *hal2, u16 addr, u16 val) | ||
| 129 | { | ||
| 130 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
| 131 | |||
| 132 | hal2_write(val, ®s->idr0); | ||
| 133 | hal2_write(0, ®s->idr1); | ||
| 134 | hal2_write(0, ®s->idr2); | ||
| 135 | hal2_write(0, ®s->idr3); | ||
| 136 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
| 137 | H2_INDIRECT_WAIT(regs); | ||
| 138 | } | ||
| 139 | |||
| 140 | static void hal2_i_write32(struct snd_hal2 *hal2, u16 addr, u32 val) | ||
| 141 | { | ||
| 142 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
| 143 | |||
| 144 | hal2_write(val & 0xffff, ®s->idr0); | ||
| 145 | hal2_write(val >> 16, ®s->idr1); | ||
| 146 | hal2_write(0, ®s->idr2); | ||
| 147 | hal2_write(0, ®s->idr3); | ||
| 148 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
| 149 | H2_INDIRECT_WAIT(regs); | ||
| 150 | } | ||
| 151 | |||
| 152 | static void hal2_i_setbit16(struct snd_hal2 *hal2, u16 addr, u16 bit) | ||
| 153 | { | ||
| 154 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
| 155 | |||
| 156 | hal2_write(H2_READ_ADDR(addr), ®s->iar); | ||
| 157 | H2_INDIRECT_WAIT(regs); | ||
| 158 | hal2_write((hal2_read(®s->idr0) & 0xffff) | bit, ®s->idr0); | ||
| 159 | hal2_write(0, ®s->idr1); | ||
| 160 | hal2_write(0, ®s->idr2); | ||
| 161 | hal2_write(0, ®s->idr3); | ||
| 162 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
| 163 | H2_INDIRECT_WAIT(regs); | ||
| 164 | } | ||
| 165 | |||
| 166 | static void hal2_i_clearbit16(struct snd_hal2 *hal2, u16 addr, u16 bit) | ||
| 167 | { | ||
| 168 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
| 169 | |||
| 170 | hal2_write(H2_READ_ADDR(addr), ®s->iar); | ||
| 171 | H2_INDIRECT_WAIT(regs); | ||
| 172 | hal2_write((hal2_read(®s->idr0) & 0xffff) & ~bit, ®s->idr0); | ||
| 173 | hal2_write(0, ®s->idr1); | ||
| 174 | hal2_write(0, ®s->idr2); | ||
| 175 | hal2_write(0, ®s->idr3); | ||
| 176 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
| 177 | H2_INDIRECT_WAIT(regs); | ||
| 178 | } | ||
| 179 | |||
| 180 | static int hal2_gain_info(struct snd_kcontrol *kcontrol, | ||
| 181 | struct snd_ctl_elem_info *uinfo) | ||
| 182 | { | ||
| 183 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 184 | uinfo->count = 2; | ||
| 185 | uinfo->value.integer.min = 0; | ||
| 186 | switch ((int)kcontrol->private_value) { | ||
| 187 | case H2_MIX_OUTPUT_ATT: | ||
| 188 | uinfo->value.integer.max = 31; | ||
| 189 | break; | ||
| 190 | case H2_MIX_INPUT_GAIN: | ||
| 191 | uinfo->value.integer.max = 15; | ||
| 192 | break; | ||
| 193 | } | ||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static int hal2_gain_get(struct snd_kcontrol *kcontrol, | ||
| 198 | struct snd_ctl_elem_value *ucontrol) | ||
| 199 | { | ||
| 200 | struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol); | ||
| 201 | u32 tmp; | ||
| 202 | int l, r; | ||
| 203 | |||
| 204 | switch ((int)kcontrol->private_value) { | ||
| 205 | case H2_MIX_OUTPUT_ATT: | ||
| 206 | tmp = hal2_i_read32(hal2, H2I_DAC_C2); | ||
| 207 | if (tmp & H2I_C2_MUTE) { | ||
| 208 | l = 0; | ||
| 209 | r = 0; | ||
| 210 | } else { | ||
| 211 | l = 31 - ((tmp >> H2I_C2_L_ATT_SHIFT) & 31); | ||
| 212 | r = 31 - ((tmp >> H2I_C2_R_ATT_SHIFT) & 31); | ||
| 213 | } | ||
| 214 | break; | ||
| 215 | case H2_MIX_INPUT_GAIN: | ||
| 216 | tmp = hal2_i_read32(hal2, H2I_ADC_C2); | ||
| 217 | l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15; | ||
| 218 | r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15; | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | ucontrol->value.integer.value[0] = l; | ||
| 222 | ucontrol->value.integer.value[1] = r; | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | static int hal2_gain_put(struct snd_kcontrol *kcontrol, | ||
| 228 | struct snd_ctl_elem_value *ucontrol) | ||
| 229 | { | ||
| 230 | struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol); | ||
| 231 | u32 old, new; | ||
| 232 | int l, r; | ||
| 233 | |||
| 234 | l = ucontrol->value.integer.value[0]; | ||
| 235 | r = ucontrol->value.integer.value[1]; | ||
| 236 | |||
| 237 | switch ((int)kcontrol->private_value) { | ||
| 238 | case H2_MIX_OUTPUT_ATT: | ||
| 239 | old = hal2_i_read32(hal2, H2I_DAC_C2); | ||
| 240 | new = old & ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE); | ||
| 241 | if (l | r) { | ||
| 242 | l = 31 - l; | ||
| 243 | r = 31 - r; | ||
| 244 | new |= (l << H2I_C2_L_ATT_SHIFT); | ||
| 245 | new |= (r << H2I_C2_R_ATT_SHIFT); | ||
| 246 | } else | ||
| 247 | new |= H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE; | ||
| 248 | hal2_i_write32(hal2, H2I_DAC_C2, new); | ||
| 249 | break; | ||
| 250 | case H2_MIX_INPUT_GAIN: | ||
| 251 | old = hal2_i_read32(hal2, H2I_ADC_C2); | ||
| 252 | new = old & ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M); | ||
| 253 | new |= (l << H2I_C2_L_GAIN_SHIFT); | ||
| 254 | new |= (r << H2I_C2_R_GAIN_SHIFT); | ||
| 255 | hal2_i_write32(hal2, H2I_ADC_C2, new); | ||
| 256 | break; | ||
| 257 | } | ||
| 258 | return old != new; | ||
| 259 | } | ||
| 260 | |||
| 261 | static struct snd_kcontrol_new hal2_ctrl_headphone __devinitdata = { | ||
| 262 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 263 | .name = "Headphone Playback Volume", | ||
| 264 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 265 | .private_value = H2_MIX_OUTPUT_ATT, | ||
| 266 | .info = hal2_gain_info, | ||
| 267 | .get = hal2_gain_get, | ||
| 268 | .put = hal2_gain_put, | ||
| 269 | }; | ||
| 270 | |||
| 271 | static struct snd_kcontrol_new hal2_ctrl_mic __devinitdata = { | ||
| 272 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 273 | .name = "Mic Capture Volume", | ||
| 274 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 275 | .private_value = H2_MIX_INPUT_GAIN, | ||
| 276 | .info = hal2_gain_info, | ||
| 277 | .get = hal2_gain_get, | ||
| 278 | .put = hal2_gain_put, | ||
| 279 | }; | ||
| 280 | |||
| 281 | static int __devinit hal2_mixer_create(struct snd_hal2 *hal2) | ||
| 282 | { | ||
| 283 | int err; | ||
| 284 | |||
| 285 | /* mute DAC */ | ||
| 286 | hal2_i_write32(hal2, H2I_DAC_C2, | ||
| 287 | H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE); | ||
| 288 | /* mute ADC */ | ||
| 289 | hal2_i_write32(hal2, H2I_ADC_C2, 0); | ||
| 290 | |||
| 291 | err = snd_ctl_add(hal2->card, | ||
| 292 | snd_ctl_new1(&hal2_ctrl_headphone, hal2)); | ||
| 293 | if (err < 0) | ||
| 294 | return err; | ||
| 295 | |||
| 296 | err = snd_ctl_add(hal2->card, | ||
| 297 | snd_ctl_new1(&hal2_ctrl_mic, hal2)); | ||
| 298 | if (err < 0) | ||
| 299 | return err; | ||
| 300 | |||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static irqreturn_t hal2_interrupt(int irq, void *dev_id) | ||
| 305 | { | ||
| 306 | struct snd_hal2 *hal2 = dev_id; | ||
| 307 | irqreturn_t ret = IRQ_NONE; | ||
| 308 | |||
| 309 | /* decide what caused this interrupt */ | ||
| 310 | if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) { | ||
| 311 | snd_pcm_period_elapsed(hal2->dac.substream); | ||
| 312 | ret = IRQ_HANDLED; | ||
| 313 | } | ||
| 314 | if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) { | ||
| 315 | snd_pcm_period_elapsed(hal2->adc.substream); | ||
| 316 | ret = IRQ_HANDLED; | ||
| 317 | } | ||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate) | ||
| 322 | { | ||
| 323 | unsigned short mod; | ||
| 324 | |||
| 325 | if (44100 % rate < 48000 % rate) { | ||
| 326 | mod = 4 * 44100 / rate; | ||
| 327 | codec->master = 44100; | ||
| 328 | } else { | ||
| 329 | mod = 4 * 48000 / rate; | ||
| 330 | codec->master = 48000; | ||
| 331 | } | ||
| 332 | |||
| 333 | codec->inc = 4; | ||
| 334 | codec->mod = mod; | ||
| 335 | rate = 4 * codec->master / mod; | ||
| 336 | |||
| 337 | return rate; | ||
| 338 | } | ||
| 339 | |||
| 340 | static void hal2_set_dac_rate(struct snd_hal2 *hal2) | ||
| 341 | { | ||
| 342 | unsigned int master = hal2->dac.master; | ||
| 343 | int inc = hal2->dac.inc; | ||
| 344 | int mod = hal2->dac.mod; | ||
| 345 | |||
| 346 | hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0); | ||
| 347 | hal2_i_write32(hal2, H2I_BRES1_C2, | ||
| 348 | ((0xffff & (inc - mod - 1)) << 16) | inc); | ||
| 349 | } | ||
| 350 | |||
| 351 | static void hal2_set_adc_rate(struct snd_hal2 *hal2) | ||
| 352 | { | ||
| 353 | unsigned int master = hal2->adc.master; | ||
| 354 | int inc = hal2->adc.inc; | ||
| 355 | int mod = hal2->adc.mod; | ||
| 356 | |||
| 357 | hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0); | ||
| 358 | hal2_i_write32(hal2, H2I_BRES2_C2, | ||
| 359 | ((0xffff & (inc - mod - 1)) << 16) | inc); | ||
| 360 | } | ||
| 361 | |||
| 362 | static void hal2_setup_dac(struct snd_hal2 *hal2) | ||
| 363 | { | ||
| 364 | unsigned int fifobeg, fifoend, highwater, sample_size; | ||
| 365 | struct hal2_pbus *pbus = &hal2->dac.pbus; | ||
| 366 | |||
| 367 | /* Now we set up some PBUS information. The PBUS needs information about | ||
| 368 | * what portion of the fifo it will use. If it's receiving or | ||
| 369 | * transmitting, and finally whether the stream is little endian or big | ||
| 370 | * endian. The information is written later, on the start call. | ||
| 371 | */ | ||
| 372 | sample_size = 2 * hal2->dac.voices; | ||
| 373 | /* Fifo should be set to hold exactly four samples. Highwater mark | ||
| 374 | * should be set to two samples. */ | ||
| 375 | highwater = (sample_size * 2) >> 1; /* halfwords */ | ||
| 376 | fifobeg = 0; /* playback is first */ | ||
| 377 | fifoend = (sample_size * 4) >> 3; /* doublewords */ | ||
| 378 | pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD | | ||
| 379 | (highwater << 8) | (fifobeg << 16) | (fifoend << 24); | ||
| 380 | /* We disable everything before we do anything at all */ | ||
| 381 | pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
| 382 | hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); | ||
| 383 | /* Setup the HAL2 for playback */ | ||
| 384 | hal2_set_dac_rate(hal2); | ||
| 385 | /* Set endianess */ | ||
| 386 | hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX); | ||
| 387 | /* Set DMA bus */ | ||
| 388 | hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); | ||
| 389 | /* We are using 1st Bresenham clock generator for playback */ | ||
| 390 | hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) | ||
| 391 | | (1 << H2I_C1_CLKID_SHIFT) | ||
| 392 | | (hal2->dac.voices << H2I_C1_DATAT_SHIFT)); | ||
| 393 | } | ||
| 394 | |||
| 395 | static void hal2_setup_adc(struct snd_hal2 *hal2) | ||
| 396 | { | ||
| 397 | unsigned int fifobeg, fifoend, highwater, sample_size; | ||
| 398 | struct hal2_pbus *pbus = &hal2->adc.pbus; | ||
| 399 | |||
| 400 | sample_size = 2 * hal2->adc.voices; | ||
| 401 | highwater = (sample_size * 2) >> 1; /* halfwords */ | ||
| 402 | fifobeg = (4 * 4) >> 3; /* record is second */ | ||
| 403 | fifoend = (4 * 4 + sample_size * 4) >> 3; /* doublewords */ | ||
| 404 | pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD | | ||
| 405 | (highwater << 8) | (fifobeg << 16) | (fifoend << 24); | ||
| 406 | pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
| 407 | hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); | ||
| 408 | /* Setup the HAL2 for record */ | ||
| 409 | hal2_set_adc_rate(hal2); | ||
| 410 | /* Set endianess */ | ||
| 411 | hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR); | ||
| 412 | /* Set DMA bus */ | ||
| 413 | hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); | ||
| 414 | /* We are using 2nd Bresenham clock generator for record */ | ||
| 415 | hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) | ||
| 416 | | (2 << H2I_C1_CLKID_SHIFT) | ||
| 417 | | (hal2->adc.voices << H2I_C1_DATAT_SHIFT)); | ||
| 418 | } | ||
| 419 | |||
| 420 | static void hal2_start_dac(struct snd_hal2 *hal2) | ||
| 421 | { | ||
| 422 | struct hal2_pbus *pbus = &hal2->dac.pbus; | ||
| 423 | |||
| 424 | pbus->pbus->pbdma_dptr = hal2->dac.desc_dma; | ||
| 425 | pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; | ||
| 426 | /* enable DAC */ | ||
| 427 | hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); | ||
| 428 | } | ||
| 429 | |||
| 430 | static void hal2_start_adc(struct snd_hal2 *hal2) | ||
| 431 | { | ||
| 432 | struct hal2_pbus *pbus = &hal2->adc.pbus; | ||
| 433 | |||
| 434 | pbus->pbus->pbdma_dptr = hal2->adc.desc_dma; | ||
| 435 | pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; | ||
| 436 | /* enable ADC */ | ||
| 437 | hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); | ||
| 438 | } | ||
| 439 | |||
| 440 | static inline void hal2_stop_dac(struct snd_hal2 *hal2) | ||
| 441 | { | ||
| 442 | hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
| 443 | /* The HAL2 itself may remain enabled safely */ | ||
| 444 | } | ||
| 445 | |||
| 446 | static inline void hal2_stop_adc(struct snd_hal2 *hal2) | ||
| 447 | { | ||
| 448 | hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
| 449 | } | ||
| 450 | |||
| 451 | static int hal2_alloc_dmabuf(struct hal2_codec *codec) | ||
| 452 | { | ||
| 453 | struct hal2_desc *desc; | ||
| 454 | dma_addr_t desc_dma, buffer_dma; | ||
| 455 | int count = H2_BUF_SIZE / H2_BLOCK_SIZE; | ||
| 456 | int i; | ||
| 457 | |||
| 458 | codec->buffer = dma_alloc_noncoherent(NULL, H2_BUF_SIZE, | ||
| 459 | &buffer_dma, GFP_KERNEL); | ||
| 460 | if (!codec->buffer) | ||
| 461 | return -ENOMEM; | ||
| 462 | desc = dma_alloc_noncoherent(NULL, count * sizeof(struct hal2_desc), | ||
| 463 | &desc_dma, GFP_KERNEL); | ||
| 464 | if (!desc) { | ||
| 465 | dma_free_noncoherent(NULL, H2_BUF_SIZE, | ||
| 466 | codec->buffer, buffer_dma); | ||
| 467 | return -ENOMEM; | ||
| 468 | } | ||
| 469 | codec->buffer_dma = buffer_dma; | ||
| 470 | codec->desc_dma = desc_dma; | ||
| 471 | codec->desc = desc; | ||
| 472 | for (i = 0; i < count; i++) { | ||
| 473 | desc->desc.pbuf = buffer_dma + i * H2_BLOCK_SIZE; | ||
| 474 | desc->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE; | ||
| 475 | desc->desc.pnext = (i == count - 1) ? | ||
| 476 | desc_dma : desc_dma + (i + 1) * sizeof(struct hal2_desc); | ||
| 477 | desc++; | ||
| 478 | } | ||
| 479 | dma_cache_sync(NULL, codec->desc, count * sizeof(struct hal2_desc), | ||
| 480 | DMA_TO_DEVICE); | ||
| 481 | codec->desc_count = count; | ||
| 482 | return 0; | ||
| 483 | } | ||
| 484 | |||
| 485 | static void hal2_free_dmabuf(struct hal2_codec *codec) | ||
| 486 | { | ||
| 487 | dma_free_noncoherent(NULL, codec->desc_count * sizeof(struct hal2_desc), | ||
| 488 | codec->desc, codec->desc_dma); | ||
| 489 | dma_free_noncoherent(NULL, H2_BUF_SIZE, codec->buffer, | ||
| 490 | codec->buffer_dma); | ||
| 491 | } | ||
| 492 | |||
| 493 | static struct snd_pcm_hardware hal2_pcm_hw = { | ||
| 494 | .info = (SNDRV_PCM_INFO_MMAP | | ||
| 495 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 496 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 497 | SNDRV_PCM_INFO_BLOCK_TRANSFER), | ||
| 498 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
| 499 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
| 500 | .rate_min = 8000, | ||
| 501 | .rate_max = 48000, | ||
| 502 | .channels_min = 2, | ||
| 503 | .channels_max = 2, | ||
| 504 | .buffer_bytes_max = 65536, | ||
| 505 | .period_bytes_min = 1024, | ||
| 506 | .period_bytes_max = 65536, | ||
| 507 | .periods_min = 2, | ||
| 508 | .periods_max = 1024, | ||
| 509 | }; | ||
| 510 | |||
| 511 | static int hal2_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 512 | struct snd_pcm_hw_params *params) | ||
| 513 | { | ||
| 514 | int err; | ||
| 515 | |||
| 516 | err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 517 | if (err < 0) | ||
| 518 | return err; | ||
| 519 | |||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int hal2_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 524 | { | ||
| 525 | return snd_pcm_lib_free_pages(substream); | ||
| 526 | } | ||
| 527 | |||
| 528 | static int hal2_playback_open(struct snd_pcm_substream *substream) | ||
| 529 | { | ||
| 530 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 531 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 532 | int err; | ||
| 533 | |||
| 534 | runtime->hw = hal2_pcm_hw; | ||
| 535 | |||
| 536 | err = hal2_alloc_dmabuf(&hal2->dac); | ||
| 537 | if (err) | ||
| 538 | return err; | ||
| 539 | return 0; | ||
| 540 | } | ||
| 541 | |||
| 542 | static int hal2_playback_close(struct snd_pcm_substream *substream) | ||
| 543 | { | ||
| 544 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 545 | |||
| 546 | hal2_free_dmabuf(&hal2->dac); | ||
| 547 | return 0; | ||
| 548 | } | ||
| 549 | |||
| 550 | static int hal2_playback_prepare(struct snd_pcm_substream *substream) | ||
| 551 | { | ||
| 552 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 553 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 554 | struct hal2_codec *dac = &hal2->dac; | ||
| 555 | |||
| 556 | dac->voices = runtime->channels; | ||
| 557 | dac->sample_rate = hal2_compute_rate(dac, runtime->rate); | ||
| 558 | memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect)); | ||
| 559 | dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; | ||
| 560 | dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
| 561 | dac->substream = substream; | ||
| 562 | hal2_setup_dac(hal2); | ||
| 563 | return 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 567 | { | ||
| 568 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 569 | |||
| 570 | switch (cmd) { | ||
| 571 | case SNDRV_PCM_TRIGGER_START: | ||
| 572 | hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma; | ||
| 573 | hal2->dac.pcm_indirect.hw_data = 0; | ||
| 574 | substream->ops->ack(substream); | ||
| 575 | hal2_start_dac(hal2); | ||
| 576 | break; | ||
| 577 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 578 | hal2_stop_dac(hal2); | ||
| 579 | break; | ||
| 580 | default: | ||
| 581 | return -EINVAL; | ||
| 582 | } | ||
| 583 | return 0; | ||
| 584 | } | ||
| 585 | |||
| 586 | static snd_pcm_uframes_t | ||
| 587 | hal2_playback_pointer(struct snd_pcm_substream *substream) | ||
| 588 | { | ||
| 589 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 590 | struct hal2_codec *dac = &hal2->dac; | ||
| 591 | |||
| 592 | return snd_pcm_indirect_playback_pointer(substream, &dac->pcm_indirect, | ||
| 593 | dac->pbus.pbus->pbdma_bptr); | ||
| 594 | } | ||
| 595 | |||
| 596 | static void hal2_playback_transfer(struct snd_pcm_substream *substream, | ||
| 597 | struct snd_pcm_indirect *rec, size_t bytes) | ||
| 598 | { | ||
| 599 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 600 | unsigned char *buf = hal2->dac.buffer + rec->hw_data; | ||
| 601 | |||
| 602 | memcpy(buf, substream->runtime->dma_area + rec->sw_data, bytes); | ||
| 603 | dma_cache_sync(NULL, buf, bytes, DMA_TO_DEVICE); | ||
| 604 | |||
| 605 | } | ||
| 606 | |||
| 607 | static int hal2_playback_ack(struct snd_pcm_substream *substream) | ||
| 608 | { | ||
| 609 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 610 | struct hal2_codec *dac = &hal2->dac; | ||
| 611 | |||
| 612 | dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; | ||
| 613 | snd_pcm_indirect_playback_transfer(substream, | ||
| 614 | &dac->pcm_indirect, | ||
| 615 | hal2_playback_transfer); | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | static int hal2_capture_open(struct snd_pcm_substream *substream) | ||
| 620 | { | ||
| 621 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 622 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 623 | struct hal2_codec *adc = &hal2->adc; | ||
| 624 | int err; | ||
| 625 | |||
| 626 | runtime->hw = hal2_pcm_hw; | ||
| 627 | |||
| 628 | err = hal2_alloc_dmabuf(adc); | ||
| 629 | if (err) | ||
| 630 | return err; | ||
| 631 | return 0; | ||
| 632 | } | ||
| 633 | |||
| 634 | static int hal2_capture_close(struct snd_pcm_substream *substream) | ||
| 635 | { | ||
| 636 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 637 | |||
| 638 | hal2_free_dmabuf(&hal2->adc); | ||
| 639 | return 0; | ||
| 640 | } | ||
| 641 | |||
| 642 | static int hal2_capture_prepare(struct snd_pcm_substream *substream) | ||
| 643 | { | ||
| 644 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 645 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 646 | struct hal2_codec *adc = &hal2->adc; | ||
| 647 | |||
| 648 | adc->voices = runtime->channels; | ||
| 649 | adc->sample_rate = hal2_compute_rate(adc, runtime->rate); | ||
| 650 | memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect)); | ||
| 651 | adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; | ||
| 652 | adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; | ||
| 653 | adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
| 654 | adc->substream = substream; | ||
| 655 | hal2_setup_adc(hal2); | ||
| 656 | return 0; | ||
| 657 | } | ||
| 658 | |||
| 659 | static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 660 | { | ||
| 661 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 662 | |||
| 663 | switch (cmd) { | ||
| 664 | case SNDRV_PCM_TRIGGER_START: | ||
| 665 | hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma; | ||
| 666 | hal2->adc.pcm_indirect.hw_data = 0; | ||
| 667 | printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma); | ||
| 668 | hal2_start_adc(hal2); | ||
| 669 | break; | ||
| 670 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 671 | hal2_stop_adc(hal2); | ||
| 672 | break; | ||
| 673 | default: | ||
| 674 | return -EINVAL; | ||
| 675 | } | ||
| 676 | return 0; | ||
| 677 | } | ||
| 678 | |||
| 679 | static snd_pcm_uframes_t | ||
| 680 | hal2_capture_pointer(struct snd_pcm_substream *substream) | ||
| 681 | { | ||
| 682 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 683 | struct hal2_codec *adc = &hal2->adc; | ||
| 684 | |||
| 685 | return snd_pcm_indirect_capture_pointer(substream, &adc->pcm_indirect, | ||
| 686 | adc->pbus.pbus->pbdma_bptr); | ||
| 687 | } | ||
| 688 | |||
| 689 | static void hal2_capture_transfer(struct snd_pcm_substream *substream, | ||
| 690 | struct snd_pcm_indirect *rec, size_t bytes) | ||
| 691 | { | ||
| 692 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 693 | unsigned char *buf = hal2->adc.buffer + rec->hw_data; | ||
| 694 | |||
| 695 | dma_cache_sync(NULL, buf, bytes, DMA_FROM_DEVICE); | ||
| 696 | memcpy(substream->runtime->dma_area + rec->sw_data, buf, bytes); | ||
| 697 | } | ||
| 698 | |||
| 699 | static int hal2_capture_ack(struct snd_pcm_substream *substream) | ||
| 700 | { | ||
| 701 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
| 702 | struct hal2_codec *adc = &hal2->adc; | ||
| 703 | |||
| 704 | snd_pcm_indirect_capture_transfer(substream, | ||
| 705 | &adc->pcm_indirect, | ||
| 706 | hal2_capture_transfer); | ||
| 707 | return 0; | ||
| 708 | } | ||
| 709 | |||
| 710 | static struct snd_pcm_ops hal2_playback_ops = { | ||
| 711 | .open = hal2_playback_open, | ||
| 712 | .close = hal2_playback_close, | ||
| 713 | .ioctl = snd_pcm_lib_ioctl, | ||
| 714 | .hw_params = hal2_pcm_hw_params, | ||
| 715 | .hw_free = hal2_pcm_hw_free, | ||
| 716 | .prepare = hal2_playback_prepare, | ||
| 717 | .trigger = hal2_playback_trigger, | ||
| 718 | .pointer = hal2_playback_pointer, | ||
| 719 | .ack = hal2_playback_ack, | ||
| 720 | }; | ||
| 721 | |||
| 722 | static struct snd_pcm_ops hal2_capture_ops = { | ||
| 723 | .open = hal2_capture_open, | ||
| 724 | .close = hal2_capture_close, | ||
| 725 | .ioctl = snd_pcm_lib_ioctl, | ||
| 726 | .hw_params = hal2_pcm_hw_params, | ||
| 727 | .hw_free = hal2_pcm_hw_free, | ||
| 728 | .prepare = hal2_capture_prepare, | ||
| 729 | .trigger = hal2_capture_trigger, | ||
| 730 | .pointer = hal2_capture_pointer, | ||
| 731 | .ack = hal2_capture_ack, | ||
| 732 | }; | ||
| 733 | |||
| 734 | static int __devinit hal2_pcm_create(struct snd_hal2 *hal2) | ||
| 735 | { | ||
| 736 | struct snd_pcm *pcm; | ||
| 737 | int err; | ||
| 738 | |||
| 739 | /* create first pcm device with one outputs and one input */ | ||
| 740 | err = snd_pcm_new(hal2->card, "SGI HAL2 Audio", 0, 1, 1, &pcm); | ||
| 741 | if (err < 0) | ||
| 742 | return err; | ||
| 743 | |||
| 744 | pcm->private_data = hal2; | ||
| 745 | strcpy(pcm->name, "SGI HAL2"); | ||
| 746 | |||
| 747 | /* set operators */ | ||
| 748 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
| 749 | &hal2_playback_ops); | ||
| 750 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
| 751 | &hal2_capture_ops); | ||
| 752 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
| 753 | snd_dma_continuous_data(GFP_KERNEL), | ||
| 754 | 0, 1024 * 1024); | ||
| 755 | |||
| 756 | return 0; | ||
| 757 | } | ||
| 758 | |||
| 759 | static int hal2_dev_free(struct snd_device *device) | ||
| 760 | { | ||
| 761 | struct snd_hal2 *hal2 = device->device_data; | ||
| 762 | |||
| 763 | free_irq(SGI_HPCDMA_IRQ, hal2); | ||
| 764 | kfree(hal2); | ||
| 765 | return 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | static struct snd_device_ops hal2_ops = { | ||
| 769 | .dev_free = hal2_dev_free, | ||
| 770 | }; | ||
| 771 | |||
| 772 | static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3, | ||
| 773 | int index) | ||
| 774 | { | ||
| 775 | codec->pbus.pbusnr = index; | ||
| 776 | codec->pbus.pbus = &hpc3->pbdma[index]; | ||
| 777 | } | ||
| 778 | |||
| 779 | static int hal2_detect(struct snd_hal2 *hal2) | ||
| 780 | { | ||
| 781 | unsigned short board, major, minor; | ||
| 782 | unsigned short rev; | ||
| 783 | |||
| 784 | /* reset HAL2 */ | ||
| 785 | hal2_write(0, &hal2->ctl_regs->isr); | ||
| 786 | |||
| 787 | /* release reset */ | ||
| 788 | hal2_write(H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N, | ||
| 789 | &hal2->ctl_regs->isr); | ||
| 790 | |||
| 791 | |||
| 792 | hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE); | ||
| 793 | rev = hal2_read(&hal2->ctl_regs->rev); | ||
| 794 | if (rev & H2_REV_AUDIO_PRESENT) | ||
| 795 | return -ENODEV; | ||
| 796 | |||
| 797 | board = (rev & H2_REV_BOARD_M) >> 12; | ||
| 798 | major = (rev & H2_REV_MAJOR_CHIP_M) >> 4; | ||
| 799 | minor = (rev & H2_REV_MINOR_CHIP_M); | ||
| 800 | |||
| 801 | printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n", | ||
| 802 | board, major, minor); | ||
| 803 | |||
| 804 | return 0; | ||
| 805 | } | ||
| 806 | |||
| 807 | static int hal2_create(struct snd_card *card, struct snd_hal2 **rchip) | ||
| 808 | { | ||
| 809 | struct snd_hal2 *hal2; | ||
| 810 | struct hpc3_regs *hpc3 = hpc3c0; | ||
| 811 | int err; | ||
| 812 | |||
| 813 | hal2 = kzalloc(sizeof(struct snd_hal2), GFP_KERNEL); | ||
| 814 | if (!hal2) | ||
| 815 | return -ENOMEM; | ||
| 816 | |||
| 817 | hal2->card = card; | ||
| 818 | |||
| 819 | if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED, | ||
| 820 | "SGI HAL2", hal2)) { | ||
| 821 | printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ); | ||
| 822 | kfree(hal2); | ||
| 823 | return -EAGAIN; | ||
| 824 | } | ||
| 825 | |||
| 826 | hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0]; | ||
| 827 | hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1]; | ||
| 828 | hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2]; | ||
| 829 | hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3]; | ||
| 830 | |||
| 831 | if (hal2_detect(hal2) < 0) { | ||
| 832 | kfree(hal2); | ||
| 833 | return -ENODEV; | ||
| 834 | } | ||
| 835 | |||
| 836 | hal2_init_codec(&hal2->dac, hpc3, 0); | ||
| 837 | hal2_init_codec(&hal2->adc, hpc3, 1); | ||
| 838 | |||
| 839 | /* | ||
| 840 | * All DMA channel interfaces in HAL2 are designed to operate with | ||
| 841 | * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles | ||
| 842 | * in D5. HAL2 is a 16-bit device which can accept both big and little | ||
| 843 | * endian format. It assumes that even address bytes are on high | ||
| 844 | * portion of PBUS (15:8) and assumes that HPC3 is programmed to | ||
| 845 | * accept a live (unsynchronized) version of P_DREQ_N from HAL2. | ||
| 846 | */ | ||
| 847 | #define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \ | ||
| 848 | (2 << HPC3_DMACFG_D4R_SHIFT) | \ | ||
| 849 | (2 << HPC3_DMACFG_D5R_SHIFT) | \ | ||
| 850 | (0 << HPC3_DMACFG_D3W_SHIFT) | \ | ||
| 851 | (2 << HPC3_DMACFG_D4W_SHIFT) | \ | ||
| 852 | (2 << HPC3_DMACFG_D5W_SHIFT) | \ | ||
| 853 | HPC3_DMACFG_DS16 | \ | ||
| 854 | HPC3_DMACFG_EVENHI | \ | ||
| 855 | HPC3_DMACFG_RTIME | \ | ||
| 856 | (8 << HPC3_DMACFG_BURST_SHIFT) | \ | ||
| 857 | HPC3_DMACFG_DRQLIVE) | ||
| 858 | /* | ||
| 859 | * Ignore what's mentioned in the specification and write value which | ||
| 860 | * works in The Real World (TM) | ||
| 861 | */ | ||
| 862 | hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844; | ||
| 863 | hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844; | ||
| 864 | |||
| 865 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, hal2, &hal2_ops); | ||
| 866 | if (err < 0) { | ||
| 867 | free_irq(SGI_HPCDMA_IRQ, hal2); | ||
| 868 | kfree(hal2); | ||
| 869 | return err; | ||
| 870 | } | ||
| 871 | *rchip = hal2; | ||
| 872 | return 0; | ||
| 873 | } | ||
| 874 | |||
| 875 | static int __devinit hal2_probe(struct platform_device *pdev) | ||
| 876 | { | ||
| 877 | struct snd_card *card; | ||
| 878 | struct snd_hal2 *chip; | ||
| 879 | int err; | ||
| 880 | |||
| 881 | card = snd_card_new(index, id, THIS_MODULE, 0); | ||
| 882 | if (card == NULL) | ||
| 883 | return -ENOMEM; | ||
| 884 | |||
| 885 | err = hal2_create(card, &chip); | ||
| 886 | if (err < 0) { | ||
| 887 | snd_card_free(card); | ||
| 888 | return err; | ||
| 889 | } | ||
| 890 | snd_card_set_dev(card, &pdev->dev); | ||
| 891 | |||
| 892 | err = hal2_pcm_create(chip); | ||
| 893 | if (err < 0) { | ||
| 894 | snd_card_free(card); | ||
| 895 | return err; | ||
| 896 | } | ||
| 897 | err = hal2_mixer_create(chip); | ||
| 898 | if (err < 0) { | ||
| 899 | snd_card_free(card); | ||
| 900 | return err; | ||
| 901 | } | ||
| 902 | |||
| 903 | strcpy(card->driver, "SGI HAL2 Audio"); | ||
| 904 | strcpy(card->shortname, "SGI HAL2 Audio"); | ||
| 905 | sprintf(card->longname, "%s irq %i", | ||
| 906 | card->shortname, | ||
| 907 | SGI_HPCDMA_IRQ); | ||
| 908 | |||
| 909 | err = snd_card_register(card); | ||
| 910 | if (err < 0) { | ||
| 911 | snd_card_free(card); | ||
| 912 | return err; | ||
| 913 | } | ||
| 914 | platform_set_drvdata(pdev, card); | ||
| 915 | return 0; | ||
| 916 | } | ||
| 917 | |||
| 918 | static int __exit hal2_remove(struct platform_device *pdev) | ||
| 919 | { | ||
| 920 | struct snd_card *card = platform_get_drvdata(pdev); | ||
| 921 | |||
| 922 | snd_card_free(card); | ||
| 923 | platform_set_drvdata(pdev, NULL); | ||
| 924 | return 0; | ||
| 925 | } | ||
| 926 | |||
| 927 | static struct platform_driver hal2_driver = { | ||
| 928 | .probe = hal2_probe, | ||
| 929 | .remove = __devexit_p(hal2_remove), | ||
| 930 | .driver = { | ||
| 931 | .name = "sgihal2", | ||
| 932 | .owner = THIS_MODULE, | ||
| 933 | } | ||
| 934 | }; | ||
| 935 | |||
| 936 | static int __init alsa_card_hal2_init(void) | ||
| 937 | { | ||
| 938 | return platform_driver_register(&hal2_driver); | ||
| 939 | } | ||
| 940 | |||
| 941 | static void __exit alsa_card_hal2_exit(void) | ||
| 942 | { | ||
| 943 | platform_driver_unregister(&hal2_driver); | ||
| 944 | } | ||
| 945 | |||
| 946 | module_init(alsa_card_hal2_init); | ||
| 947 | module_exit(alsa_card_hal2_exit); | ||
diff --git a/sound/mips/hal2.h b/sound/mips/hal2.h new file mode 100644 index 000000000000..f19828bc64e0 --- /dev/null +++ b/sound/mips/hal2.h | |||
| @@ -0,0 +1,245 @@ | |||
| 1 | #ifndef __HAL2_H | ||
| 2 | #define __HAL2_H | ||
| 3 | |||
| 4 | /* | ||
| 5 | * Driver for HAL2 sound processors | ||
| 6 | * Copyright (c) 1999 Ulf Carlsson <ulfc@bun.falkenberg.se> | ||
| 7 | * Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org> | ||
| 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 | * 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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/types.h> | ||
| 25 | |||
| 26 | /* Indirect status register */ | ||
| 27 | |||
| 28 | #define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */ | ||
| 29 | #define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */ | ||
| 30 | #define H2_ISR_QUAD_MODE 0x04 /* codec mode 0=indigo 1=quad */ | ||
| 31 | #define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */ | ||
| 32 | #define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */ | ||
| 33 | |||
| 34 | /* Revision register */ | ||
| 35 | |||
| 36 | #define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */ | ||
| 37 | #define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */ | ||
| 38 | #define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */ | ||
| 39 | #define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */ | ||
| 40 | |||
| 41 | /* Indirect address register */ | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Address of indirect internal register to be accessed. A write to this | ||
| 45 | * register initiates read or write access to the indirect registers in the | ||
| 46 | * HAL2. Note that there af four indirect data registers for write access to | ||
| 47 | * registers larger than 16 byte. | ||
| 48 | */ | ||
| 49 | |||
| 50 | #define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */ | ||
| 51 | /* block the register resides in */ | ||
| 52 | /* 1=DMA Port */ | ||
| 53 | /* 9=Global DMA Control */ | ||
| 54 | /* 2=Bresenham */ | ||
| 55 | /* 3=Unix Timer */ | ||
| 56 | #define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */ | ||
| 57 | /* blockin which the indirect */ | ||
| 58 | /* register resides */ | ||
| 59 | /* If IAR_TYPE_M=DMA Port: */ | ||
| 60 | /* 1=Synth In */ | ||
| 61 | /* 2=AES In */ | ||
| 62 | /* 3=AES Out */ | ||
| 63 | /* 4=DAC Out */ | ||
| 64 | /* 5=ADC Out */ | ||
| 65 | /* 6=Synth Control */ | ||
| 66 | /* If IAR_TYPE_M=Global DMA Control: */ | ||
| 67 | /* 1=Control */ | ||
| 68 | /* If IAR_TYPE_M=Bresenham: */ | ||
| 69 | /* 1=Bresenham Clock Gen 1 */ | ||
| 70 | /* 2=Bresenham Clock Gen 2 */ | ||
| 71 | /* 3=Bresenham Clock Gen 3 */ | ||
| 72 | /* If IAR_TYPE_M=Unix Timer: */ | ||
| 73 | /* 1=Unix Timer */ | ||
| 74 | #define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */ | ||
| 75 | #define H2_IAR_PARAM 0x000C /* Parameter Select */ | ||
| 76 | #define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */ | ||
| 77 | /* 00:word0 */ | ||
| 78 | /* 01:word1 */ | ||
| 79 | /* 10:word2 */ | ||
| 80 | /* 11:word3 */ | ||
| 81 | /* | ||
| 82 | * HAL2 internal addressing | ||
| 83 | * | ||
| 84 | * The HAL2 has "indirect registers" (idr) which are accessed by writing to the | ||
| 85 | * Indirect Data registers. Write the address to the Indirect Address register | ||
| 86 | * to transfer the data. | ||
| 87 | * | ||
| 88 | * We define the H2IR_* to the read address and H2IW_* to the write address and | ||
| 89 | * H2I_* to be fields in whatever register is referred to. | ||
| 90 | * | ||
| 91 | * When we write to indirect registers which are larger than one word (16 bit) | ||
| 92 | * we have to fill more than one indirect register before writing. When we read | ||
| 93 | * back however we have to read several times, each time with different Read | ||
| 94 | * Back Indexes (there are defs for doing this easily). | ||
| 95 | */ | ||
| 96 | |||
| 97 | /* | ||
| 98 | * Relay Control | ||
| 99 | */ | ||
| 100 | #define H2I_RELAY_C 0x9100 | ||
| 101 | #define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */ | ||
| 102 | |||
| 103 | /* DMA port enable */ | ||
| 104 | |||
| 105 | #define H2I_DMA_PORT_EN 0x9104 | ||
| 106 | #define H2I_DMA_PORT_EN_SY_IN 0x01 /* Synth_in DMA port */ | ||
| 107 | #define H2I_DMA_PORT_EN_AESRX 0x02 /* AES receiver DMA port */ | ||
| 108 | #define H2I_DMA_PORT_EN_AESTX 0x04 /* AES transmitter DMA port */ | ||
| 109 | #define H2I_DMA_PORT_EN_CODECTX 0x08 /* CODEC transmit DMA port */ | ||
| 110 | #define H2I_DMA_PORT_EN_CODECR 0x10 /* CODEC receive DMA port */ | ||
| 111 | |||
| 112 | #define H2I_DMA_END 0x9108 /* global dma endian select */ | ||
| 113 | #define H2I_DMA_END_SY_IN 0x01 /* Synth_in DMA port */ | ||
| 114 | #define H2I_DMA_END_AESRX 0x02 /* AES receiver DMA port */ | ||
| 115 | #define H2I_DMA_END_AESTX 0x04 /* AES transmitter DMA port */ | ||
| 116 | #define H2I_DMA_END_CODECTX 0x08 /* CODEC transmit DMA port */ | ||
| 117 | #define H2I_DMA_END_CODECR 0x10 /* CODEC receive DMA port */ | ||
| 118 | /* 0=b_end 1=l_end */ | ||
| 119 | |||
| 120 | #define H2I_DMA_DRV 0x910C /* global PBUS DMA enable */ | ||
| 121 | |||
| 122 | #define H2I_SYNTH_C 0x1104 /* Synth DMA control */ | ||
| 123 | |||
| 124 | #define H2I_AESRX_C 0x1204 /* AES RX dma control */ | ||
| 125 | |||
| 126 | #define H2I_C_TS_EN 0x20 /* Timestamp enable */ | ||
| 127 | #define H2I_C_TS_FRMT 0x40 /* Timestamp format */ | ||
| 128 | #define H2I_C_NAUDIO 0x80 /* Sign extend */ | ||
| 129 | |||
| 130 | /* AESRX CTL, 16 bit */ | ||
| 131 | |||
| 132 | #define H2I_AESTX_C 0x1304 /* AES TX DMA control */ | ||
| 133 | #define H2I_AESTX_C_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ | ||
| 134 | #define H2I_AESTX_C_CLKID_M 0x18 | ||
| 135 | #define H2I_AESTX_C_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ | ||
| 136 | #define H2I_AESTX_C_DATAT_M 0x300 | ||
| 137 | |||
| 138 | /* CODEC registers */ | ||
| 139 | |||
| 140 | #define H2I_DAC_C1 0x1404 /* DAC DMA control, 16 bit */ | ||
| 141 | #define H2I_DAC_C2 0x1408 /* DAC DMA control, 32 bit */ | ||
| 142 | #define H2I_ADC_C1 0x1504 /* ADC DMA control, 16 bit */ | ||
| 143 | #define H2I_ADC_C2 0x1508 /* ADC DMA control, 32 bit */ | ||
| 144 | |||
| 145 | /* Bits in CTL1 register */ | ||
| 146 | |||
| 147 | #define H2I_C1_DMA_SHIFT 0 /* DMA channel */ | ||
| 148 | #define H2I_C1_DMA_M 0x7 | ||
| 149 | #define H2I_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ | ||
| 150 | #define H2I_C1_CLKID_M 0x18 | ||
| 151 | #define H2I_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ | ||
| 152 | #define H2I_C1_DATAT_M 0x300 | ||
| 153 | |||
| 154 | /* Bits in CTL2 register */ | ||
| 155 | |||
| 156 | #define H2I_C2_R_GAIN_SHIFT 0 /* right a/d input gain */ | ||
| 157 | #define H2I_C2_R_GAIN_M 0xf | ||
| 158 | #define H2I_C2_L_GAIN_SHIFT 4 /* left a/d input gain */ | ||
| 159 | #define H2I_C2_L_GAIN_M 0xf0 | ||
| 160 | #define H2I_C2_R_SEL 0x100 /* right input select */ | ||
| 161 | #define H2I_C2_L_SEL 0x200 /* left input select */ | ||
| 162 | #define H2I_C2_MUTE 0x400 /* mute */ | ||
| 163 | #define H2I_C2_DO1 0x00010000 /* digital output port bit 0 */ | ||
| 164 | #define H2I_C2_DO2 0x00020000 /* digital output port bit 1 */ | ||
| 165 | #define H2I_C2_R_ATT_SHIFT 18 /* right d/a output - */ | ||
| 166 | #define H2I_C2_R_ATT_M 0x007c0000 /* attenuation */ | ||
| 167 | #define H2I_C2_L_ATT_SHIFT 23 /* left d/a output - */ | ||
| 168 | #define H2I_C2_L_ATT_M 0x0f800000 /* attenuation */ | ||
| 169 | |||
| 170 | #define H2I_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl */ | ||
| 171 | |||
| 172 | /* Clock generator CTL 1, 16 bit */ | ||
| 173 | |||
| 174 | #define H2I_BRES1_C1 0x2104 | ||
| 175 | #define H2I_BRES2_C1 0x2204 | ||
| 176 | #define H2I_BRES3_C1 0x2304 | ||
| 177 | |||
| 178 | #define H2I_BRES_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */ | ||
| 179 | #define H2I_BRES_C1_M 0x03 | ||
| 180 | |||
| 181 | /* Clock generator CTL 2, 32 bit */ | ||
| 182 | |||
| 183 | #define H2I_BRES1_C2 0x2108 | ||
| 184 | #define H2I_BRES2_C2 0x2208 | ||
| 185 | #define H2I_BRES3_C2 0x2308 | ||
| 186 | |||
| 187 | #define H2I_BRES_C2_INC_SHIFT 0 /* increment value */ | ||
| 188 | #define H2I_BRES_C2_INC_M 0xffff | ||
| 189 | #define H2I_BRES_C2_MOD_SHIFT 16 /* modcontrol value */ | ||
| 190 | #define H2I_BRES_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */ | ||
| 191 | |||
| 192 | /* Unix timer, 64 bit */ | ||
| 193 | |||
| 194 | #define H2I_UTIME 0x3104 | ||
| 195 | #define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */ | ||
| 196 | #define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */ | ||
| 197 | #define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */ | ||
| 198 | #define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */ | ||
| 199 | #define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */ | ||
| 200 | |||
| 201 | struct hal2_ctl_regs { | ||
| 202 | u32 _unused0[4]; | ||
| 203 | u32 isr; /* 0x10 Status Register */ | ||
| 204 | u32 _unused1[3]; | ||
| 205 | u32 rev; /* 0x20 Revision Register */ | ||
| 206 | u32 _unused2[3]; | ||
| 207 | u32 iar; /* 0x30 Indirect Address Register */ | ||
| 208 | u32 _unused3[3]; | ||
| 209 | u32 idr0; /* 0x40 Indirect Data Register 0 */ | ||
| 210 | u32 _unused4[3]; | ||
| 211 | u32 idr1; /* 0x50 Indirect Data Register 1 */ | ||
| 212 | u32 _unused5[3]; | ||
| 213 | u32 idr2; /* 0x60 Indirect Data Register 2 */ | ||
| 214 | u32 _unused6[3]; | ||
| 215 | u32 idr3; /* 0x70 Indirect Data Register 3 */ | ||
| 216 | }; | ||
| 217 | |||
| 218 | struct hal2_aes_regs { | ||
| 219 | u32 rx_stat[2]; /* Status registers */ | ||
| 220 | u32 rx_cr[2]; /* Control registers */ | ||
| 221 | u32 rx_ud[4]; /* User data window */ | ||
| 222 | u32 rx_st[24]; /* Channel status data */ | ||
| 223 | |||
| 224 | u32 tx_stat[1]; /* Status register */ | ||
| 225 | u32 tx_cr[3]; /* Control registers */ | ||
| 226 | u32 tx_ud[4]; /* User data window */ | ||
| 227 | u32 tx_st[24]; /* Channel status data */ | ||
| 228 | }; | ||
| 229 | |||
| 230 | struct hal2_vol_regs { | ||
| 231 | u32 right; /* Right volume */ | ||
| 232 | u32 left; /* Left volume */ | ||
| 233 | }; | ||
| 234 | |||
| 235 | struct hal2_syn_regs { | ||
| 236 | u32 _unused0[2]; | ||
| 237 | u32 page; /* DOC Page register */ | ||
| 238 | u32 regsel; /* DOC Register selection */ | ||
| 239 | u32 dlow; /* DOC Data low */ | ||
| 240 | u32 dhigh; /* DOC Data high */ | ||
| 241 | u32 irq; /* IRQ Status */ | ||
| 242 | u32 dram; /* DRAM Access */ | ||
| 243 | }; | ||
| 244 | |||
| 245 | #endif /* __HAL2_H */ | ||
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c new file mode 100644 index 000000000000..4c63504348dc --- /dev/null +++ b/sound/mips/sgio2audio.c | |||
| @@ -0,0 +1,1006 @@ | |||
| 1 | /* | ||
| 2 | * Sound driver for Silicon Graphics O2 Workstations A/V board audio. | ||
| 3 | * | ||
| 4 | * Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org> | ||
| 5 | * Copyright 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de> | ||
| 6 | * Mxier part taken from mace_audio.c: | ||
| 7 | * Copyright 2007 Thorben Jändling <tj.trevelyan@gmail.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/spinlock.h> | ||
| 28 | #include <linux/gfp.h> | ||
| 29 | #include <linux/vmalloc.h> | ||
| 30 | #include <linux/interrupt.h> | ||
| 31 | #include <linux/dma-mapping.h> | ||
| 32 | #include <linux/platform_device.h> | ||
| 33 | #include <linux/io.h> | ||
| 34 | |||
| 35 | #include <asm/ip32/ip32_ints.h> | ||
| 36 | #include <asm/ip32/mace.h> | ||
| 37 | |||
| 38 | #include <sound/core.h> | ||
| 39 | #include <sound/control.h> | ||
| 40 | #include <sound/pcm.h> | ||
| 41 | #define SNDRV_GET_ID | ||
| 42 | #include <sound/initval.h> | ||
| 43 | #include <sound/ad1843.h> | ||
| 44 | |||
| 45 | |||
| 46 | MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org>"); | ||
| 47 | MODULE_DESCRIPTION("SGI O2 Audio"); | ||
| 48 | MODULE_LICENSE("GPL"); | ||
| 49 | MODULE_SUPPORTED_DEVICE("{{Silicon Graphics, O2 Audio}}"); | ||
| 50 | |||
| 51 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | ||
| 52 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | ||
| 53 | |||
| 54 | module_param(index, int, 0444); | ||
| 55 | MODULE_PARM_DESC(index, "Index value for SGI O2 soundcard."); | ||
| 56 | module_param(id, charp, 0444); | ||
| 57 | MODULE_PARM_DESC(id, "ID string for SGI O2 soundcard."); | ||
| 58 | |||
| 59 | |||
| 60 | #define AUDIO_CONTROL_RESET BIT(0) /* 1: reset audio interface */ | ||
| 61 | #define AUDIO_CONTROL_CODEC_PRESENT BIT(1) /* 1: codec detected */ | ||
| 62 | |||
| 63 | #define CODEC_CONTROL_WORD_SHIFT 0 | ||
| 64 | #define CODEC_CONTROL_READ BIT(16) | ||
| 65 | #define CODEC_CONTROL_ADDRESS_SHIFT 17 | ||
| 66 | |||
| 67 | #define CHANNEL_CONTROL_RESET BIT(10) /* 1: reset channel */ | ||
| 68 | #define CHANNEL_DMA_ENABLE BIT(9) /* 1: enable DMA transfer */ | ||
| 69 | #define CHANNEL_INT_THRESHOLD_DISABLED (0 << 5) /* interrupt disabled */ | ||
| 70 | #define CHANNEL_INT_THRESHOLD_25 (1 << 5) /* int on buffer >25% full */ | ||
| 71 | #define CHANNEL_INT_THRESHOLD_50 (2 << 5) /* int on buffer >50% full */ | ||
| 72 | #define CHANNEL_INT_THRESHOLD_75 (3 << 5) /* int on buffer >75% full */ | ||
| 73 | #define CHANNEL_INT_THRESHOLD_EMPTY (4 << 5) /* int on buffer empty */ | ||
| 74 | #define CHANNEL_INT_THRESHOLD_NOT_EMPTY (5 << 5) /* int on buffer !empty */ | ||
| 75 | #define CHANNEL_INT_THRESHOLD_FULL (6 << 5) /* int on buffer empty */ | ||
| 76 | #define CHANNEL_INT_THRESHOLD_NOT_FULL (7 << 5) /* int on buffer !empty */ | ||
| 77 | |||
| 78 | #define CHANNEL_RING_SHIFT 12 | ||
| 79 | #define CHANNEL_RING_SIZE (1 << CHANNEL_RING_SHIFT) | ||
| 80 | #define CHANNEL_RING_MASK (CHANNEL_RING_SIZE - 1) | ||
| 81 | |||
| 82 | #define CHANNEL_LEFT_SHIFT 40 | ||
| 83 | #define CHANNEL_RIGHT_SHIFT 8 | ||
| 84 | |||
| 85 | struct snd_sgio2audio_chan { | ||
| 86 | int idx; | ||
| 87 | struct snd_pcm_substream *substream; | ||
| 88 | int pos; | ||
| 89 | snd_pcm_uframes_t size; | ||
| 90 | spinlock_t lock; | ||
| 91 | }; | ||
| 92 | |||
| 93 | /* definition of the chip-specific record */ | ||
| 94 | struct snd_sgio2audio { | ||
| 95 | struct snd_card *card; | ||
| 96 | |||
| 97 | /* codec */ | ||
| 98 | struct snd_ad1843 ad1843; | ||
| 99 | spinlock_t ad1843_lock; | ||
| 100 | |||
| 101 | /* channels */ | ||
| 102 | struct snd_sgio2audio_chan channel[3]; | ||
| 103 | |||
| 104 | /* resources */ | ||
| 105 | void *ring_base; | ||
| 106 | dma_addr_t ring_base_dma; | ||
| 107 | }; | ||
| 108 | |||
| 109 | /* AD1843 access */ | ||
| 110 | |||
| 111 | /* | ||
| 112 | * read_ad1843_reg returns the current contents of a 16 bit AD1843 register. | ||
| 113 | * | ||
| 114 | * Returns unsigned register value on success, -errno on failure. | ||
| 115 | */ | ||
| 116 | static int read_ad1843_reg(void *priv, int reg) | ||
| 117 | { | ||
| 118 | struct snd_sgio2audio *chip = priv; | ||
| 119 | int val; | ||
| 120 | unsigned long flags; | ||
| 121 | |||
| 122 | spin_lock_irqsave(&chip->ad1843_lock, flags); | ||
| 123 | |||
| 124 | writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | | ||
| 125 | CODEC_CONTROL_READ, &mace->perif.audio.codec_control); | ||
| 126 | wmb(); | ||
| 127 | val = readq(&mace->perif.audio.codec_control); /* flush bus */ | ||
| 128 | udelay(200); | ||
| 129 | |||
| 130 | val = readq(&mace->perif.audio.codec_read); | ||
| 131 | |||
| 132 | spin_unlock_irqrestore(&chip->ad1843_lock, flags); | ||
| 133 | return val; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * write_ad1843_reg writes the specified value to a 16 bit AD1843 register. | ||
| 138 | */ | ||
| 139 | static int write_ad1843_reg(void *priv, int reg, int word) | ||
| 140 | { | ||
| 141 | struct snd_sgio2audio *chip = priv; | ||
| 142 | int val; | ||
| 143 | unsigned long flags; | ||
| 144 | |||
| 145 | spin_lock_irqsave(&chip->ad1843_lock, flags); | ||
| 146 | |||
| 147 | writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | | ||
| 148 | (word << CODEC_CONTROL_WORD_SHIFT), | ||
| 149 | &mace->perif.audio.codec_control); | ||
| 150 | wmb(); | ||
| 151 | val = readq(&mace->perif.audio.codec_control); /* flush bus */ | ||
| 152 | udelay(200); | ||
| 153 | |||
| 154 | spin_unlock_irqrestore(&chip->ad1843_lock, flags); | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | static int sgio2audio_gain_info(struct snd_kcontrol *kcontrol, | ||
| 159 | struct snd_ctl_elem_info *uinfo) | ||
| 160 | { | ||
| 161 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
| 162 | |||
| 163 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 164 | uinfo->count = 2; | ||
| 165 | uinfo->value.integer.min = 0; | ||
| 166 | uinfo->value.integer.max = ad1843_get_gain_max(&chip->ad1843, | ||
| 167 | (int)kcontrol->private_value); | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | static int sgio2audio_gain_get(struct snd_kcontrol *kcontrol, | ||
| 172 | struct snd_ctl_elem_value *ucontrol) | ||
| 173 | { | ||
| 174 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
| 175 | int vol; | ||
| 176 | |||
| 177 | vol = ad1843_get_gain(&chip->ad1843, (int)kcontrol->private_value); | ||
| 178 | |||
| 179 | ucontrol->value.integer.value[0] = (vol >> 8) & 0xFF; | ||
| 180 | ucontrol->value.integer.value[1] = vol & 0xFF; | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int sgio2audio_gain_put(struct snd_kcontrol *kcontrol, | ||
| 186 | struct snd_ctl_elem_value *ucontrol) | ||
| 187 | { | ||
| 188 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
| 189 | int newvol, oldvol; | ||
| 190 | |||
| 191 | oldvol = ad1843_get_gain(&chip->ad1843, kcontrol->private_value); | ||
| 192 | newvol = (ucontrol->value.integer.value[0] << 8) | | ||
| 193 | ucontrol->value.integer.value[1]; | ||
| 194 | |||
| 195 | newvol = ad1843_set_gain(&chip->ad1843, kcontrol->private_value, | ||
| 196 | newvol); | ||
| 197 | |||
| 198 | return newvol != oldvol; | ||
| 199 | } | ||
| 200 | |||
| 201 | static int sgio2audio_source_info(struct snd_kcontrol *kcontrol, | ||
| 202 | struct snd_ctl_elem_info *uinfo) | ||
| 203 | { | ||
| 204 | static const char *texts[3] = { | ||
| 205 | "Cam Mic", "Mic", "Line" | ||
| 206 | }; | ||
| 207 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 208 | uinfo->count = 1; | ||
| 209 | uinfo->value.enumerated.items = 3; | ||
| 210 | if (uinfo->value.enumerated.item >= 3) | ||
| 211 | uinfo->value.enumerated.item = 1; | ||
| 212 | strcpy(uinfo->value.enumerated.name, | ||
| 213 | texts[uinfo->value.enumerated.item]); | ||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | static int sgio2audio_source_get(struct snd_kcontrol *kcontrol, | ||
| 218 | struct snd_ctl_elem_value *ucontrol) | ||
| 219 | { | ||
| 220 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
| 221 | |||
| 222 | ucontrol->value.enumerated.item[0] = ad1843_get_recsrc(&chip->ad1843); | ||
| 223 | return 0; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int sgio2audio_source_put(struct snd_kcontrol *kcontrol, | ||
| 227 | struct snd_ctl_elem_value *ucontrol) | ||
| 228 | { | ||
| 229 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
| 230 | int newsrc, oldsrc; | ||
| 231 | |||
| 232 | oldsrc = ad1843_get_recsrc(&chip->ad1843); | ||
| 233 | newsrc = ad1843_set_recsrc(&chip->ad1843, | ||
| 234 | ucontrol->value.enumerated.item[0]); | ||
| 235 | |||
| 236 | return newsrc != oldsrc; | ||
| 237 | } | ||
| 238 | |||
| 239 | /* dac1/pcm0 mixer control */ | ||
| 240 | static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 __devinitdata = { | ||
| 241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 242 | .name = "PCM Playback Volume", | ||
| 243 | .index = 0, | ||
| 244 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 245 | .private_value = AD1843_GAIN_PCM_0, | ||
| 246 | .info = sgio2audio_gain_info, | ||
| 247 | .get = sgio2audio_gain_get, | ||
| 248 | .put = sgio2audio_gain_put, | ||
| 249 | }; | ||
| 250 | |||
| 251 | /* dac2/pcm1 mixer control */ | ||
| 252 | static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 __devinitdata = { | ||
| 253 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 254 | .name = "PCM Playback Volume", | ||
| 255 | .index = 1, | ||
| 256 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 257 | .private_value = AD1843_GAIN_PCM_1, | ||
| 258 | .info = sgio2audio_gain_info, | ||
| 259 | .get = sgio2audio_gain_get, | ||
| 260 | .put = sgio2audio_gain_put, | ||
| 261 | }; | ||
| 262 | |||
| 263 | /* record level mixer control */ | ||
| 264 | static struct snd_kcontrol_new sgio2audio_ctrl_reclevel __devinitdata = { | ||
| 265 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 266 | .name = "Capture Volume", | ||
| 267 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 268 | .private_value = AD1843_GAIN_RECLEV, | ||
| 269 | .info = sgio2audio_gain_info, | ||
| 270 | .get = sgio2audio_gain_get, | ||
| 271 | .put = sgio2audio_gain_put, | ||
| 272 | }; | ||
| 273 | |||
| 274 | /* record level source control */ | ||
| 275 | static struct snd_kcontrol_new sgio2audio_ctrl_recsource __devinitdata = { | ||
| 276 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 277 | .name = "Capture Source", | ||
| 278 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 279 | .info = sgio2audio_source_info, | ||
| 280 | .get = sgio2audio_source_get, | ||
| 281 | .put = sgio2audio_source_put, | ||
| 282 | }; | ||
| 283 | |||
| 284 | /* line mixer control */ | ||
| 285 | static struct snd_kcontrol_new sgio2audio_ctrl_line __devinitdata = { | ||
| 286 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 287 | .name = "Line Playback Volume", | ||
| 288 | .index = 0, | ||
| 289 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 290 | .private_value = AD1843_GAIN_LINE, | ||
| 291 | .info = sgio2audio_gain_info, | ||
| 292 | .get = sgio2audio_gain_get, | ||
| 293 | .put = sgio2audio_gain_put, | ||
| 294 | }; | ||
| 295 | |||
| 296 | /* cd mixer control */ | ||
| 297 | static struct snd_kcontrol_new sgio2audio_ctrl_cd __devinitdata = { | ||
| 298 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 299 | .name = "Line Playback Volume", | ||
| 300 | .index = 1, | ||
| 301 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 302 | .private_value = AD1843_GAIN_LINE_2, | ||
| 303 | .info = sgio2audio_gain_info, | ||
| 304 | .get = sgio2audio_gain_get, | ||
| 305 | .put = sgio2audio_gain_put, | ||
| 306 | }; | ||
| 307 | |||
| 308 | /* mic mixer control */ | ||
| 309 | static struct snd_kcontrol_new sgio2audio_ctrl_mic __devinitdata = { | ||
| 310 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 311 | .name = "Mic Playback Volume", | ||
| 312 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 313 | .private_value = AD1843_GAIN_MIC, | ||
| 314 | .info = sgio2audio_gain_info, | ||
| 315 | .get = sgio2audio_gain_get, | ||
| 316 | .put = sgio2audio_gain_put, | ||
| 317 | }; | ||
| 318 | |||
| 319 | |||
| 320 | static int __devinit snd_sgio2audio_new_mixer(struct snd_sgio2audio *chip) | ||
| 321 | { | ||
| 322 | int err; | ||
| 323 | |||
| 324 | err = snd_ctl_add(chip->card, | ||
| 325 | snd_ctl_new1(&sgio2audio_ctrl_pcm0, chip)); | ||
| 326 | if (err < 0) | ||
| 327 | return err; | ||
| 328 | |||
| 329 | err = snd_ctl_add(chip->card, | ||
| 330 | snd_ctl_new1(&sgio2audio_ctrl_pcm1, chip)); | ||
| 331 | if (err < 0) | ||
| 332 | return err; | ||
| 333 | |||
| 334 | err = snd_ctl_add(chip->card, | ||
| 335 | snd_ctl_new1(&sgio2audio_ctrl_reclevel, chip)); | ||
| 336 | if (err < 0) | ||
| 337 | return err; | ||
| 338 | |||
| 339 | err = snd_ctl_add(chip->card, | ||
| 340 | snd_ctl_new1(&sgio2audio_ctrl_recsource, chip)); | ||
| 341 | if (err < 0) | ||
| 342 | return err; | ||
| 343 | err = snd_ctl_add(chip->card, | ||
| 344 | snd_ctl_new1(&sgio2audio_ctrl_line, chip)); | ||
| 345 | if (err < 0) | ||
| 346 | return err; | ||
| 347 | |||
| 348 | err = snd_ctl_add(chip->card, | ||
| 349 | snd_ctl_new1(&sgio2audio_ctrl_cd, chip)); | ||
| 350 | if (err < 0) | ||
| 351 | return err; | ||
| 352 | |||
| 353 | err = snd_ctl_add(chip->card, | ||
| 354 | snd_ctl_new1(&sgio2audio_ctrl_mic, chip)); | ||
| 355 | if (err < 0) | ||
| 356 | return err; | ||
| 357 | |||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | /* low-level audio interface DMA */ | ||
| 362 | |||
| 363 | /* get data out of bounce buffer, count must be a multiple of 32 */ | ||
| 364 | /* returns 1 if a period has elapsed */ | ||
| 365 | static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip, | ||
| 366 | unsigned int ch, unsigned int count) | ||
| 367 | { | ||
| 368 | int ret; | ||
| 369 | unsigned long src_base, src_pos, dst_mask; | ||
| 370 | unsigned char *dst_base; | ||
| 371 | int dst_pos; | ||
| 372 | u64 *src; | ||
| 373 | s16 *dst; | ||
| 374 | u64 x; | ||
| 375 | unsigned long flags; | ||
| 376 | struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; | ||
| 377 | |||
| 378 | spin_lock_irqsave(&chip->channel[ch].lock, flags); | ||
| 379 | |||
| 380 | src_base = (unsigned long) chip->ring_base | (ch << CHANNEL_RING_SHIFT); | ||
| 381 | src_pos = readq(&mace->perif.audio.chan[ch].read_ptr); | ||
| 382 | dst_base = runtime->dma_area; | ||
| 383 | dst_pos = chip->channel[ch].pos; | ||
| 384 | dst_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1; | ||
| 385 | |||
| 386 | /* check if a period has elapsed */ | ||
| 387 | chip->channel[ch].size += (count >> 3); /* in frames */ | ||
| 388 | ret = chip->channel[ch].size >= runtime->period_size; | ||
| 389 | chip->channel[ch].size %= runtime->period_size; | ||
| 390 | |||
| 391 | while (count) { | ||
| 392 | src = (u64 *)(src_base + src_pos); | ||
| 393 | dst = (s16 *)(dst_base + dst_pos); | ||
| 394 | |||
| 395 | x = *src; | ||
| 396 | dst[0] = (x >> CHANNEL_LEFT_SHIFT) & 0xffff; | ||
| 397 | dst[1] = (x >> CHANNEL_RIGHT_SHIFT) & 0xffff; | ||
| 398 | |||
| 399 | src_pos = (src_pos + sizeof(u64)) & CHANNEL_RING_MASK; | ||
| 400 | dst_pos = (dst_pos + 2 * sizeof(s16)) & dst_mask; | ||
| 401 | count -= sizeof(u64); | ||
| 402 | } | ||
| 403 | |||
| 404 | writeq(src_pos, &mace->perif.audio.chan[ch].read_ptr); /* in bytes */ | ||
| 405 | chip->channel[ch].pos = dst_pos; | ||
| 406 | |||
| 407 | spin_unlock_irqrestore(&chip->channel[ch].lock, flags); | ||
| 408 | return ret; | ||
| 409 | } | ||
| 410 | |||
| 411 | /* put some DMA data in bounce buffer, count must be a multiple of 32 */ | ||
| 412 | /* returns 1 if a period has elapsed */ | ||
| 413 | static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip, | ||
| 414 | unsigned int ch, unsigned int count) | ||
| 415 | { | ||
| 416 | int ret; | ||
| 417 | s64 l, r; | ||
| 418 | unsigned long dst_base, dst_pos, src_mask; | ||
| 419 | unsigned char *src_base; | ||
| 420 | int src_pos; | ||
| 421 | u64 *dst; | ||
| 422 | s16 *src; | ||
| 423 | unsigned long flags; | ||
| 424 | struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; | ||
| 425 | |||
| 426 | spin_lock_irqsave(&chip->channel[ch].lock, flags); | ||
| 427 | |||
| 428 | dst_base = (unsigned long)chip->ring_base | (ch << CHANNEL_RING_SHIFT); | ||
| 429 | dst_pos = readq(&mace->perif.audio.chan[ch].write_ptr); | ||
| 430 | src_base = runtime->dma_area; | ||
| 431 | src_pos = chip->channel[ch].pos; | ||
| 432 | src_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1; | ||
| 433 | |||
| 434 | /* check if a period has elapsed */ | ||
| 435 | chip->channel[ch].size += (count >> 3); /* in frames */ | ||
| 436 | ret = chip->channel[ch].size >= runtime->period_size; | ||
| 437 | chip->channel[ch].size %= runtime->period_size; | ||
| 438 | |||
| 439 | while (count) { | ||
| 440 | src = (s16 *)(src_base + src_pos); | ||
| 441 | dst = (u64 *)(dst_base + dst_pos); | ||
| 442 | |||
| 443 | l = src[0]; /* sign extend */ | ||
| 444 | r = src[1]; /* sign extend */ | ||
| 445 | |||
| 446 | *dst = ((l & 0x00ffffff) << CHANNEL_LEFT_SHIFT) | | ||
| 447 | ((r & 0x00ffffff) << CHANNEL_RIGHT_SHIFT); | ||
| 448 | |||
| 449 | dst_pos = (dst_pos + sizeof(u64)) & CHANNEL_RING_MASK; | ||
| 450 | src_pos = (src_pos + 2 * sizeof(s16)) & src_mask; | ||
| 451 | count -= sizeof(u64); | ||
| 452 | } | ||
| 453 | |||
| 454 | writeq(dst_pos, &mace->perif.audio.chan[ch].write_ptr); /* in bytes */ | ||
| 455 | chip->channel[ch].pos = src_pos; | ||
| 456 | |||
| 457 | spin_unlock_irqrestore(&chip->channel[ch].lock, flags); | ||
| 458 | return ret; | ||
| 459 | } | ||
| 460 | |||
| 461 | static int snd_sgio2audio_dma_start(struct snd_pcm_substream *substream) | ||
| 462 | { | ||
| 463 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
| 464 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
| 465 | int ch = chan->idx; | ||
| 466 | |||
| 467 | /* reset DMA channel */ | ||
| 468 | writeq(CHANNEL_CONTROL_RESET, &mace->perif.audio.chan[ch].control); | ||
| 469 | udelay(10); | ||
| 470 | writeq(0, &mace->perif.audio.chan[ch].control); | ||
| 471 | |||
| 472 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 473 | /* push a full buffer */ | ||
| 474 | snd_sgio2audio_dma_push_frag(chip, ch, CHANNEL_RING_SIZE - 32); | ||
| 475 | } | ||
| 476 | /* set DMA to wake on 50% empty and enable interrupt */ | ||
| 477 | writeq(CHANNEL_DMA_ENABLE | CHANNEL_INT_THRESHOLD_50, | ||
| 478 | &mace->perif.audio.chan[ch].control); | ||
| 479 | return 0; | ||
| 480 | } | ||
| 481 | |||
| 482 | static int snd_sgio2audio_dma_stop(struct snd_pcm_substream *substream) | ||
| 483 | { | ||
| 484 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
| 485 | |||
| 486 | writeq(0, &mace->perif.audio.chan[chan->idx].control); | ||
| 487 | return 0; | ||
| 488 | } | ||
| 489 | |||
| 490 | static irqreturn_t snd_sgio2audio_dma_in_isr(int irq, void *dev_id) | ||
| 491 | { | ||
| 492 | struct snd_sgio2audio_chan *chan = dev_id; | ||
| 493 | struct snd_pcm_substream *substream; | ||
| 494 | struct snd_sgio2audio *chip; | ||
| 495 | int count, ch; | ||
| 496 | |||
| 497 | substream = chan->substream; | ||
| 498 | chip = snd_pcm_substream_chip(substream); | ||
| 499 | ch = chan->idx; | ||
| 500 | |||
| 501 | /* empty the ring */ | ||
| 502 | count = CHANNEL_RING_SIZE - | ||
| 503 | readq(&mace->perif.audio.chan[ch].depth) - 32; | ||
| 504 | if (snd_sgio2audio_dma_pull_frag(chip, ch, count)) | ||
| 505 | snd_pcm_period_elapsed(substream); | ||
| 506 | |||
| 507 | return IRQ_HANDLED; | ||
| 508 | } | ||
| 509 | |||
| 510 | static irqreturn_t snd_sgio2audio_dma_out_isr(int irq, void *dev_id) | ||
| 511 | { | ||
| 512 | struct snd_sgio2audio_chan *chan = dev_id; | ||
| 513 | struct snd_pcm_substream *substream; | ||
| 514 | struct snd_sgio2audio *chip; | ||
| 515 | int count, ch; | ||
| 516 | |||
| 517 | substream = chan->substream; | ||
| 518 | chip = snd_pcm_substream_chip(substream); | ||
| 519 | ch = chan->idx; | ||
| 520 | /* fill the ring */ | ||
| 521 | count = CHANNEL_RING_SIZE - | ||
| 522 | readq(&mace->perif.audio.chan[ch].depth) - 32; | ||
| 523 | if (snd_sgio2audio_dma_push_frag(chip, ch, count)) | ||
| 524 | snd_pcm_period_elapsed(substream); | ||
| 525 | |||
| 526 | return IRQ_HANDLED; | ||
| 527 | } | ||
| 528 | |||
| 529 | static irqreturn_t snd_sgio2audio_error_isr(int irq, void *dev_id) | ||
| 530 | { | ||
| 531 | struct snd_sgio2audio_chan *chan = dev_id; | ||
| 532 | struct snd_pcm_substream *substream; | ||
| 533 | |||
| 534 | substream = chan->substream; | ||
| 535 | snd_sgio2audio_dma_stop(substream); | ||
| 536 | snd_sgio2audio_dma_start(substream); | ||
| 537 | return IRQ_HANDLED; | ||
| 538 | } | ||
| 539 | |||
| 540 | /* PCM part */ | ||
| 541 | /* PCM hardware definition */ | ||
| 542 | static struct snd_pcm_hardware snd_sgio2audio_pcm_hw = { | ||
| 543 | .info = (SNDRV_PCM_INFO_MMAP | | ||
| 544 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 545 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 546 | SNDRV_PCM_INFO_BLOCK_TRANSFER), | ||
| 547 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
| 548 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
| 549 | .rate_min = 8000, | ||
| 550 | .rate_max = 48000, | ||
| 551 | .channels_min = 2, | ||
| 552 | .channels_max = 2, | ||
| 553 | .buffer_bytes_max = 65536, | ||
| 554 | .period_bytes_min = 32768, | ||
| 555 | .period_bytes_max = 65536, | ||
| 556 | .periods_min = 1, | ||
| 557 | .periods_max = 1024, | ||
| 558 | }; | ||
| 559 | |||
| 560 | /* PCM playback open callback */ | ||
| 561 | static int snd_sgio2audio_playback1_open(struct snd_pcm_substream *substream) | ||
| 562 | { | ||
| 563 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
| 564 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 565 | |||
| 566 | runtime->hw = snd_sgio2audio_pcm_hw; | ||
| 567 | runtime->private_data = &chip->channel[1]; | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | static int snd_sgio2audio_playback2_open(struct snd_pcm_substream *substream) | ||
| 572 | { | ||
| 573 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
| 574 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 575 | |||
| 576 | runtime->hw = snd_sgio2audio_pcm_hw; | ||
| 577 | runtime->private_data = &chip->channel[2]; | ||
| 578 | return 0; | ||
| 579 | } | ||
| 580 | |||
| 581 | /* PCM capture open callback */ | ||
| 582 | static int snd_sgio2audio_capture_open(struct snd_pcm_substream *substream) | ||
| 583 | { | ||
| 584 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
| 585 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 586 | |||
| 587 | runtime->hw = snd_sgio2audio_pcm_hw; | ||
| 588 | runtime->private_data = &chip->channel[0]; | ||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 592 | /* PCM close callback */ | ||
| 593 | static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) | ||
| 594 | { | ||
| 595 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 596 | |||
| 597 | runtime->private_data = NULL; | ||
| 598 | return 0; | ||
| 599 | } | ||
| 600 | |||
| 601 | |||
| 602 | /* hw_params callback */ | ||
| 603 | static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 604 | struct snd_pcm_hw_params *hw_params) | ||
| 605 | { | ||
| 606 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 607 | int size = params_buffer_bytes(hw_params); | ||
| 608 | |||
| 609 | /* alloc virtual 'dma' area */ | ||
| 610 | if (runtime->dma_area) | ||
| 611 | vfree(runtime->dma_area); | ||
| 612 | runtime->dma_area = vmalloc(size); | ||
| 613 | if (runtime->dma_area == NULL) | ||
| 614 | return -ENOMEM; | ||
| 615 | runtime->dma_bytes = size; | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | /* hw_free callback */ | ||
| 620 | static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 621 | { | ||
| 622 | if (substream->runtime->dma_area) | ||
| 623 | vfree(substream->runtime->dma_area); | ||
| 624 | substream->runtime->dma_area = NULL; | ||
| 625 | return 0; | ||
| 626 | } | ||
| 627 | |||
| 628 | /* prepare callback */ | ||
| 629 | static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream) | ||
| 630 | { | ||
| 631 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
| 632 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 633 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
| 634 | int ch = chan->idx; | ||
| 635 | unsigned long flags; | ||
| 636 | |||
| 637 | spin_lock_irqsave(&chip->channel[ch].lock, flags); | ||
| 638 | |||
| 639 | /* Setup the pseudo-dma transfer pointers. */ | ||
| 640 | chip->channel[ch].pos = 0; | ||
| 641 | chip->channel[ch].size = 0; | ||
| 642 | chip->channel[ch].substream = substream; | ||
| 643 | |||
| 644 | /* set AD1843 format */ | ||
| 645 | /* hardware format is always S16_LE */ | ||
| 646 | switch (substream->stream) { | ||
| 647 | case SNDRV_PCM_STREAM_PLAYBACK: | ||
| 648 | ad1843_setup_dac(&chip->ad1843, | ||
| 649 | ch - 1, | ||
| 650 | runtime->rate, | ||
| 651 | SNDRV_PCM_FORMAT_S16_LE, | ||
| 652 | runtime->channels); | ||
| 653 | break; | ||
| 654 | case SNDRV_PCM_STREAM_CAPTURE: | ||
| 655 | ad1843_setup_adc(&chip->ad1843, | ||
| 656 | runtime->rate, | ||
| 657 | SNDRV_PCM_FORMAT_S16_LE, | ||
| 658 | runtime->channels); | ||
| 659 | break; | ||
| 660 | } | ||
| 661 | spin_unlock_irqrestore(&chip->channel[ch].lock, flags); | ||
| 662 | return 0; | ||
| 663 | } | ||
| 664 | |||
| 665 | /* trigger callback */ | ||
| 666 | static int snd_sgio2audio_pcm_trigger(struct snd_pcm_substream *substream, | ||
| 667 | int cmd) | ||
| 668 | { | ||
| 669 | switch (cmd) { | ||
| 670 | case SNDRV_PCM_TRIGGER_START: | ||
| 671 | /* start the PCM engine */ | ||
| 672 | snd_sgio2audio_dma_start(substream); | ||
| 673 | break; | ||
| 674 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 675 | /* stop the PCM engine */ | ||
| 676 | snd_sgio2audio_dma_stop(substream); | ||
| 677 | break; | ||
| 678 | default: | ||
| 679 | return -EINVAL; | ||
| 680 | } | ||
| 681 | return 0; | ||
| 682 | } | ||
| 683 | |||
| 684 | /* pointer callback */ | ||
| 685 | static snd_pcm_uframes_t | ||
| 686 | snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream) | ||
| 687 | { | ||
| 688 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
| 689 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
| 690 | |||
| 691 | /* get the current hardware pointer */ | ||
| 692 | return bytes_to_frames(substream->runtime, | ||
| 693 | chip->channel[chan->idx].pos); | ||
| 694 | } | ||
| 695 | |||
| 696 | /* get the physical page pointer on the given offset */ | ||
| 697 | static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream, | ||
| 698 | unsigned long offset) | ||
| 699 | { | ||
| 700 | return vmalloc_to_page(substream->runtime->dma_area + offset); | ||
| 701 | } | ||
| 702 | |||
| 703 | /* operators */ | ||
| 704 | static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { | ||
| 705 | .open = snd_sgio2audio_playback1_open, | ||
| 706 | .close = snd_sgio2audio_pcm_close, | ||
| 707 | .ioctl = snd_pcm_lib_ioctl, | ||
| 708 | .hw_params = snd_sgio2audio_pcm_hw_params, | ||
| 709 | .hw_free = snd_sgio2audio_pcm_hw_free, | ||
| 710 | .prepare = snd_sgio2audio_pcm_prepare, | ||
| 711 | .trigger = snd_sgio2audio_pcm_trigger, | ||
| 712 | .pointer = snd_sgio2audio_pcm_pointer, | ||
| 713 | .page = snd_sgio2audio_page, | ||
| 714 | }; | ||
| 715 | |||
| 716 | static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { | ||
| 717 | .open = snd_sgio2audio_playback2_open, | ||
| 718 | .close = snd_sgio2audio_pcm_close, | ||
| 719 | .ioctl = snd_pcm_lib_ioctl, | ||
| 720 | .hw_params = snd_sgio2audio_pcm_hw_params, | ||
| 721 | .hw_free = snd_sgio2audio_pcm_hw_free, | ||
| 722 | .prepare = snd_sgio2audio_pcm_prepare, | ||
| 723 | .trigger = snd_sgio2audio_pcm_trigger, | ||
| 724 | .pointer = snd_sgio2audio_pcm_pointer, | ||
| 725 | .page = snd_sgio2audio_page, | ||
| 726 | }; | ||
| 727 | |||
| 728 | static struct snd_pcm_ops snd_sgio2audio_capture_ops = { | ||
| 729 | .open = snd_sgio2audio_capture_open, | ||
| 730 | .close = snd_sgio2audio_pcm_close, | ||
| 731 | .ioctl = snd_pcm_lib_ioctl, | ||
| 732 | .hw_params = snd_sgio2audio_pcm_hw_params, | ||
| 733 | .hw_free = snd_sgio2audio_pcm_hw_free, | ||
| 734 | .prepare = snd_sgio2audio_pcm_prepare, | ||
| 735 | .trigger = snd_sgio2audio_pcm_trigger, | ||
| 736 | .pointer = snd_sgio2audio_pcm_pointer, | ||
| 737 | .page = snd_sgio2audio_page, | ||
| 738 | }; | ||
| 739 | |||
| 740 | /* | ||
| 741 | * definitions of capture are omitted here... | ||
| 742 | */ | ||
| 743 | |||
| 744 | /* create a pcm device */ | ||
| 745 | static int __devinit snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) | ||
| 746 | { | ||
| 747 | struct snd_pcm *pcm; | ||
| 748 | int err; | ||
| 749 | |||
| 750 | /* create first pcm device with one outputs and one input */ | ||
| 751 | err = snd_pcm_new(chip->card, "SGI O2 Audio", 0, 1, 1, &pcm); | ||
| 752 | if (err < 0) | ||
| 753 | return err; | ||
| 754 | |||
| 755 | pcm->private_data = chip; | ||
| 756 | strcpy(pcm->name, "SGI O2 DAC1"); | ||
| 757 | |||
| 758 | /* set operators */ | ||
| 759 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
| 760 | &snd_sgio2audio_playback1_ops); | ||
| 761 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
| 762 | &snd_sgio2audio_capture_ops); | ||
| 763 | |||
| 764 | /* create second pcm device with one outputs and no input */ | ||
| 765 | err = snd_pcm_new(chip->card, "SGI O2 Audio", 1, 1, 0, &pcm); | ||
| 766 | if (err < 0) | ||
| 767 | return err; | ||
| 768 | |||
| 769 | pcm->private_data = chip; | ||
| 770 | strcpy(pcm->name, "SGI O2 DAC2"); | ||
| 771 | |||
| 772 | /* set operators */ | ||
| 773 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
| 774 | &snd_sgio2audio_playback2_ops); | ||
| 775 | |||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | static struct { | ||
| 780 | int idx; | ||
| 781 | int irq; | ||
| 782 | irqreturn_t (*isr)(int, void *); | ||
| 783 | const char *desc; | ||
| 784 | } snd_sgio2_isr_table[] = { | ||
| 785 | { | ||
| 786 | .idx = 0, | ||
| 787 | .irq = MACEISA_AUDIO1_DMAT_IRQ, | ||
| 788 | .isr = snd_sgio2audio_dma_in_isr, | ||
| 789 | .desc = "Capture DMA Channel 0" | ||
| 790 | }, { | ||
| 791 | .idx = 0, | ||
| 792 | .irq = MACEISA_AUDIO1_OF_IRQ, | ||
| 793 | .isr = snd_sgio2audio_error_isr, | ||
| 794 | .desc = "Capture Overflow" | ||
| 795 | }, { | ||
| 796 | .idx = 1, | ||
| 797 | .irq = MACEISA_AUDIO2_DMAT_IRQ, | ||
| 798 | .isr = snd_sgio2audio_dma_out_isr, | ||
| 799 | .desc = "Playback DMA Channel 1" | ||
| 800 | }, { | ||
| 801 | .idx = 1, | ||
| 802 | .irq = MACEISA_AUDIO2_MERR_IRQ, | ||
| 803 | .isr = snd_sgio2audio_error_isr, | ||
| 804 | .desc = "Memory Error Channel 1" | ||
| 805 | }, { | ||
| 806 | .idx = 2, | ||
| 807 | .irq = MACEISA_AUDIO3_DMAT_IRQ, | ||
| 808 | .isr = snd_sgio2audio_dma_out_isr, | ||
| 809 | .desc = "Playback DMA Channel 2" | ||
| 810 | }, { | ||
| 811 | .idx = 2, | ||
| 812 | .irq = MACEISA_AUDIO3_MERR_IRQ, | ||
| 813 | .isr = snd_sgio2audio_error_isr, | ||
| 814 | .desc = "Memory Error Channel 2" | ||
| 815 | } | ||
| 816 | }; | ||
| 817 | |||
| 818 | /* ALSA driver */ | ||
| 819 | |||
| 820 | static int snd_sgio2audio_free(struct snd_sgio2audio *chip) | ||
| 821 | { | ||
| 822 | int i; | ||
| 823 | |||
| 824 | /* reset interface */ | ||
| 825 | writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control); | ||
| 826 | udelay(1); | ||
| 827 | writeq(0, &mace->perif.audio.control); | ||
| 828 | |||
| 829 | /* release IRQ's */ | ||
| 830 | for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) | ||
| 831 | free_irq(snd_sgio2_isr_table[i].irq, | ||
| 832 | &chip->channel[snd_sgio2_isr_table[i].idx]); | ||
| 833 | |||
| 834 | dma_free_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, | ||
| 835 | chip->ring_base, chip->ring_base_dma); | ||
| 836 | |||
| 837 | /* release card data */ | ||
| 838 | kfree(chip); | ||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 842 | static int snd_sgio2audio_dev_free(struct snd_device *device) | ||
| 843 | { | ||
| 844 | struct snd_sgio2audio *chip = device->device_data; | ||
| 845 | |||
| 846 | return snd_sgio2audio_free(chip); | ||
| 847 | } | ||
| 848 | |||
| 849 | static struct snd_device_ops ops = { | ||
| 850 | .dev_free = snd_sgio2audio_dev_free, | ||
| 851 | }; | ||
| 852 | |||
| 853 | static int __devinit snd_sgio2audio_create(struct snd_card *card, | ||
| 854 | struct snd_sgio2audio **rchip) | ||
| 855 | { | ||
| 856 | struct snd_sgio2audio *chip; | ||
| 857 | int i, err; | ||
| 858 | |||
| 859 | *rchip = NULL; | ||
| 860 | |||
| 861 | /* check if a codec is attached to the interface */ | ||
| 862 | /* (Audio or Audio/Video board present) */ | ||
| 863 | if (!(readq(&mace->perif.audio.control) & AUDIO_CONTROL_CODEC_PRESENT)) | ||
| 864 | return -ENOENT; | ||
| 865 | |||
| 866 | chip = kzalloc(sizeof(struct snd_sgio2audio), GFP_KERNEL); | ||
| 867 | if (chip == NULL) | ||
| 868 | return -ENOMEM; | ||
| 869 | |||
| 870 | chip->card = card; | ||
| 871 | |||
| 872 | chip->ring_base = dma_alloc_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, | ||
| 873 | &chip->ring_base_dma, GFP_USER); | ||
| 874 | if (chip->ring_base == NULL) { | ||
| 875 | printk(KERN_ERR | ||
| 876 | "sgio2audio: could not allocate ring buffers\n"); | ||
| 877 | kfree(chip); | ||
| 878 | return -ENOMEM; | ||
| 879 | } | ||
| 880 | |||
| 881 | spin_lock_init(&chip->ad1843_lock); | ||
| 882 | |||
| 883 | /* initialize channels */ | ||
| 884 | for (i = 0; i < 3; i++) { | ||
| 885 | spin_lock_init(&chip->channel[i].lock); | ||
| 886 | chip->channel[i].idx = i; | ||
| 887 | } | ||
| 888 | |||
| 889 | /* allocate IRQs */ | ||
| 890 | for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) { | ||
| 891 | if (request_irq(snd_sgio2_isr_table[i].irq, | ||
| 892 | snd_sgio2_isr_table[i].isr, | ||
| 893 | 0, | ||
| 894 | snd_sgio2_isr_table[i].desc, | ||
| 895 | &chip->channel[snd_sgio2_isr_table[i].idx])) { | ||
| 896 | snd_sgio2audio_free(chip); | ||
| 897 | printk(KERN_ERR "sgio2audio: cannot allocate irq %d\n", | ||
| 898 | snd_sgio2_isr_table[i].irq); | ||
| 899 | return -EBUSY; | ||
| 900 | } | ||
| 901 | } | ||
| 902 | |||
| 903 | /* reset the interface */ | ||
| 904 | writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control); | ||
| 905 | udelay(1); | ||
| 906 | writeq(0, &mace->perif.audio.control); | ||
| 907 | msleep_interruptible(1); /* give time to recover */ | ||
| 908 | |||
| 909 | /* set ring base */ | ||
| 910 | writeq(chip->ring_base_dma, &mace->perif.ctrl.ringbase); | ||
| 911 | |||
| 912 | /* attach the AD1843 codec */ | ||
| 913 | chip->ad1843.read = read_ad1843_reg; | ||
| 914 | chip->ad1843.write = write_ad1843_reg; | ||
| 915 | chip->ad1843.chip = chip; | ||
| 916 | |||
| 917 | /* initialize the AD1843 codec */ | ||
| 918 | err = ad1843_init(&chip->ad1843); | ||
| 919 | if (err < 0) { | ||
| 920 | snd_sgio2audio_free(chip); | ||
| 921 | return err; | ||
| 922 | } | ||
| 923 | |||
| 924 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | ||
| 925 | if (err < 0) { | ||
| 926 | snd_sgio2audio_free(chip); | ||
| 927 | return err; | ||
| 928 | } | ||
| 929 | *rchip = chip; | ||
| 930 | return 0; | ||
| 931 | } | ||
| 932 | |||
| 933 | static int __devinit snd_sgio2audio_probe(struct platform_device *pdev) | ||
| 934 | { | ||
| 935 | struct snd_card *card; | ||
| 936 | struct snd_sgio2audio *chip; | ||
| 937 | int err; | ||
| 938 | |||
| 939 | card = snd_card_new(index, id, THIS_MODULE, 0); | ||
| 940 | if (card == NULL) | ||
| 941 | return -ENOMEM; | ||
| 942 | |||
| 943 | err = snd_sgio2audio_create(card, &chip); | ||
| 944 | if (err < 0) { | ||
| 945 | snd_card_free(card); | ||
| 946 | return err; | ||
| 947 | } | ||
| 948 | snd_card_set_dev(card, &pdev->dev); | ||
| 949 | |||
| 950 | err = snd_sgio2audio_new_pcm(chip); | ||
| 951 | if (err < 0) { | ||
| 952 | snd_card_free(card); | ||
| 953 | return err; | ||
| 954 | } | ||
| 955 | err = snd_sgio2audio_new_mixer(chip); | ||
| 956 | if (err < 0) { | ||
| 957 | snd_card_free(card); | ||
| 958 | return err; | ||
| 959 | } | ||
| 960 | |||
| 961 | strcpy(card->driver, "SGI O2 Audio"); | ||
| 962 | strcpy(card->shortname, "SGI O2 Audio"); | ||
| 963 | sprintf(card->longname, "%s irq %i-%i", | ||
| 964 | card->shortname, | ||
| 965 | MACEISA_AUDIO1_DMAT_IRQ, | ||
| 966 | MACEISA_AUDIO3_MERR_IRQ); | ||
| 967 | |||
| 968 | err = snd_card_register(card); | ||
| 969 | if (err < 0) { | ||
| 970 | snd_card_free(card); | ||
| 971 | return err; | ||
| 972 | } | ||
| 973 | platform_set_drvdata(pdev, card); | ||
| 974 | return 0; | ||
| 975 | } | ||
| 976 | |||
| 977 | static int __exit snd_sgio2audio_remove(struct platform_device *pdev) | ||
| 978 | { | ||
| 979 | struct snd_card *card = platform_get_drvdata(pdev); | ||
| 980 | |||
| 981 | snd_card_free(card); | ||
| 982 | platform_set_drvdata(pdev, NULL); | ||
| 983 | return 0; | ||
| 984 | } | ||
| 985 | |||
| 986 | static struct platform_driver sgio2audio_driver = { | ||
| 987 | .probe = snd_sgio2audio_probe, | ||
| 988 | .remove = __devexit_p(snd_sgio2audio_remove), | ||
| 989 | .driver = { | ||
| 990 | .name = "sgio2audio", | ||
| 991 | .owner = THIS_MODULE, | ||
| 992 | } | ||
| 993 | }; | ||
| 994 | |||
| 995 | static int __init alsa_card_sgio2audio_init(void) | ||
| 996 | { | ||
| 997 | return platform_driver_register(&sgio2audio_driver); | ||
| 998 | } | ||
| 999 | |||
| 1000 | static void __exit alsa_card_sgio2audio_exit(void) | ||
| 1001 | { | ||
| 1002 | platform_driver_unregister(&sgio2audio_driver); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | module_init(alsa_card_sgio2audio_init) | ||
| 1006 | module_exit(alsa_card_sgio2audio_exit) | ||
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 3be2dc1025b5..33940139844b 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | config SOUND_BCM_CS4297A | 8 | config SOUND_BCM_CS4297A |
| 9 | tristate "Crystal Sound CS4297a (for Swarm)" | 9 | tristate "Crystal Sound CS4297a (for Swarm)" |
| 10 | depends on SOUND_PRIME && SIBYTE_SWARM | 10 | depends on SIBYTE_SWARM |
| 11 | help | 11 | help |
| 12 | The BCM91250A has a Crystal CS4297a on synchronous serial | 12 | The BCM91250A has a Crystal CS4297a on synchronous serial |
| 13 | port B (in addition to the DB-9 serial port). Say Y or M | 13 | port B (in addition to the DB-9 serial port). Say Y or M |
| @@ -17,7 +17,7 @@ config SOUND_BCM_CS4297A | |||
| 17 | 17 | ||
| 18 | config SOUND_VWSND | 18 | config SOUND_VWSND |
| 19 | tristate "SGI Visual Workstation Sound" | 19 | tristate "SGI Visual Workstation Sound" |
| 20 | depends on SOUND_PRIME && X86_VISWS | 20 | depends on X86_VISWS |
| 21 | help | 21 | help |
| 22 | Say Y or M if you have an SGI Visual Workstation and you want to be | 22 | Say Y or M if you have an SGI Visual Workstation and you want to be |
| 23 | able to use its on-board audio. Read | 23 | able to use its on-board audio. Read |
| @@ -26,19 +26,18 @@ config SOUND_VWSND | |||
| 26 | 26 | ||
| 27 | config SOUND_HAL2 | 27 | config SOUND_HAL2 |
| 28 | tristate "SGI HAL2 sound (EXPERIMENTAL)" | 28 | tristate "SGI HAL2 sound (EXPERIMENTAL)" |
| 29 | depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL | 29 | depends on SGI_IP22 && EXPERIMENTAL |
| 30 | help | 30 | help |
| 31 | Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to | 31 | Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to |
| 32 | use its on-board A2 audio system. | 32 | use its on-board A2 audio system. |
| 33 | 33 | ||
| 34 | config SOUND_AU1550_AC97 | 34 | config SOUND_AU1550_AC97 |
| 35 | tristate "Au1550/Au1200 AC97 Sound" | 35 | tristate "Au1550/Au1200 AC97 Sound" |
| 36 | select SND_AC97_CODEC | 36 | depends on SOC_AU1550 || SOC_AU1200 |
| 37 | depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200) | ||
| 38 | 37 | ||
| 39 | config SOUND_TRIDENT | 38 | config SOUND_TRIDENT |
| 40 | tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" | 39 | tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" |
| 41 | depends on SOUND_PRIME && PCI | 40 | depends on PCI |
| 42 | ---help--- | 41 | ---help--- |
| 43 | Say Y or M if you have a PCI sound card utilizing the Trident | 42 | Say Y or M if you have a PCI sound card utilizing the Trident |
| 44 | 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 | 43 | 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 |
| @@ -79,7 +78,7 @@ config SOUND_TRIDENT | |||
| 79 | 78 | ||
| 80 | config SOUND_MSNDCLAS | 79 | config SOUND_MSNDCLAS |
| 81 | tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" | 80 | tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" |
| 82 | depends on SOUND_PRIME && (m || !STANDALONE) && ISA | 81 | depends on (m || !STANDALONE) && ISA |
| 83 | help | 82 | help |
| 84 | Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or | 83 | Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or |
| 85 | Monterey (not for the Pinnacle or Fiji). | 84 | Monterey (not for the Pinnacle or Fiji). |
| @@ -143,7 +142,7 @@ config MSNDCLAS_IO | |||
| 143 | 142 | ||
| 144 | config SOUND_MSNDPIN | 143 | config SOUND_MSNDPIN |
| 145 | tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" | 144 | tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" |
| 146 | depends on SOUND_PRIME && (m || !STANDALONE) && ISA | 145 | depends on (m || !STANDALONE) && ISA |
| 147 | help | 146 | help |
| 148 | Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. | 147 | Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. |
| 149 | See <file:Documentation/sound/oss/MultiSound> for important information | 148 | See <file:Documentation/sound/oss/MultiSound> for important information |
| @@ -229,7 +228,7 @@ config MSNDPIN_NONPNP | |||
| 229 | configure the card's resources. | 228 | configure the card's resources. |
| 230 | 229 | ||
| 231 | comment "MSND Pinnacle DSP section will be configured to above parameters." | 230 | comment "MSND Pinnacle DSP section will be configured to above parameters." |
| 232 | depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP | 231 | depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP |
| 233 | 232 | ||
| 234 | config MSNDPIN_CFG | 233 | config MSNDPIN_CFG |
| 235 | hex "MSND Pinnacle config port 250,260,270" | 234 | hex "MSND Pinnacle config port 250,260,270" |
| @@ -242,7 +241,7 @@ config MSNDPIN_CFG | |||
| 242 | Mode". | 241 | Mode". |
| 243 | 242 | ||
| 244 | comment "Pinnacle-specific Device Configuration (0 disables)" | 243 | comment "Pinnacle-specific Device Configuration (0 disables)" |
| 245 | depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP | 244 | depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP |
| 246 | 245 | ||
| 247 | config MSNDPIN_MPU_IO | 246 | config MSNDPIN_MPU_IO |
| 248 | hex "MSND Pinnacle MPU I/O (e.g. 330)" | 247 | hex "MSND Pinnacle MPU I/O (e.g. 330)" |
| @@ -294,7 +293,7 @@ config MSNDPIN_JOYSTICK_IO | |||
| 294 | 293 | ||
| 295 | config MSND_FIFOSIZE | 294 | config MSND_FIFOSIZE |
| 296 | int "MSND buffer size (kB)" | 295 | int "MSND buffer size (kB)" |
| 297 | depends on SOUND_PRIME && (SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y) | 296 | depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y |
| 298 | default "128" | 297 | default "128" |
| 299 | help | 298 | help |
| 300 | Configures the size of each audio buffer, in kilobytes, for | 299 | Configures the size of each audio buffer, in kilobytes, for |
| @@ -302,9 +301,9 @@ config MSND_FIFOSIZE | |||
| 302 | and Pinnacle). Larger values reduce the chance of data overruns at | 301 | and Pinnacle). Larger values reduce the chance of data overruns at |
| 303 | the expense of overall latency. If unsure, use the default. | 302 | the expense of overall latency. If unsure, use the default. |
| 304 | 303 | ||
| 305 | config SOUND_OSS | 304 | menuconfig SOUND_OSS |
| 306 | tristate "OSS sound modules" | 305 | tristate "OSS sound modules" |
| 307 | depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS | 306 | depends on ISA_DMA_API && VIRT_TO_BUS |
| 308 | help | 307 | help |
| 309 | OSS is the Open Sound System suite of sound card drivers. They make | 308 | OSS is the Open Sound System suite of sound card drivers. They make |
| 310 | sound programming easier since they provide a common API. Say Y or | 309 | sound programming easier since they provide a common API. Say Y or |
| @@ -312,16 +311,16 @@ config SOUND_OSS | |||
| 312 | driver for your sound card above, then pick your driver from the | 311 | driver for your sound card above, then pick your driver from the |
| 313 | list below. | 312 | list below. |
| 314 | 313 | ||
| 314 | if SOUND_OSS | ||
| 315 | |||
| 315 | config SOUND_TRACEINIT | 316 | config SOUND_TRACEINIT |
| 316 | bool "Verbose initialisation" | 317 | bool "Verbose initialisation" |
| 317 | depends on SOUND_OSS | ||
| 318 | help | 318 | help |
| 319 | Verbose soundcard initialization -- affects the format of autoprobe | 319 | Verbose soundcard initialization -- affects the format of autoprobe |
| 320 | and initialization messages at boot time. | 320 | and initialization messages at boot time. |
| 321 | 321 | ||
| 322 | config SOUND_DMAP | 322 | config SOUND_DMAP |
| 323 | bool "Persistent DMA buffers" | 323 | bool "Persistent DMA buffers" |
| 324 | depends on SOUND_OSS | ||
| 325 | ---help--- | 324 | ---help--- |
| 326 | Linux can often have problems allocating DMA buffers for ISA sound | 325 | Linux can often have problems allocating DMA buffers for ISA sound |
| 327 | cards on machines with more than 16MB of RAM. This is because ISA | 326 | cards on machines with more than 16MB of RAM. This is because ISA |
| @@ -338,8 +337,6 @@ config SOUND_DMAP | |||
| 338 | 337 | ||
| 339 | config SOUND_SSCAPE | 338 | config SOUND_SSCAPE |
| 340 | tristate "Ensoniq SoundScape support" | 339 | tristate "Ensoniq SoundScape support" |
| 341 | depends on SOUND_OSS | ||
| 342 | depends on VIRT_TO_BUS | ||
| 343 | help | 340 | help |
| 344 | Answer Y if you have a sound card based on the Ensoniq SoundScape | 341 | Answer Y if you have a sound card based on the Ensoniq SoundScape |
| 345 | chipset. Such cards are being manufactured at least by Ensoniq, Spea | 342 | chipset. Such cards are being manufactured at least by Ensoniq, Spea |
| @@ -352,13 +349,11 @@ config SOUND_SSCAPE | |||
| 352 | 349 | ||
| 353 | config SOUND_VMIDI | 350 | config SOUND_VMIDI |
| 354 | tristate "Loopback MIDI device support" | 351 | tristate "Loopback MIDI device support" |
| 355 | depends on SOUND_OSS | ||
| 356 | help | 352 | help |
| 357 | Support for MIDI loopback on port 1 or 2. | 353 | Support for MIDI loopback on port 1 or 2. |
| 358 | 354 | ||
| 359 | config SOUND_TRIX | 355 | config SOUND_TRIX |
| 360 | tristate "MediaTrix AudioTrix Pro support" | 356 | tristate "MediaTrix AudioTrix Pro support" |
| 361 | depends on SOUND_OSS | ||
| 362 | help | 357 | help |
| 363 | Answer Y if you have the AudioTriX Pro sound card manufactured | 358 | Answer Y if you have the AudioTriX Pro sound card manufactured |
| 364 | by MediaTrix. | 359 | by MediaTrix. |
| @@ -382,7 +377,6 @@ config TRIX_BOOT_FILE | |||
| 382 | 377 | ||
| 383 | config SOUND_MSS | 378 | config SOUND_MSS |
| 384 | tristate "Microsoft Sound System support" | 379 | tristate "Microsoft Sound System support" |
| 385 | depends on SOUND_OSS | ||
| 386 | ---help--- | 380 | ---help--- |
| 387 | Again think carefully before answering Y to this question. It's | 381 | Again think carefully before answering Y to this question. It's |
| 388 | safe to answer Y if you have the original Windows Sound System card | 382 | safe to answer Y if you have the original Windows Sound System card |
| @@ -414,7 +408,6 @@ config SOUND_MSS | |||
| 414 | 408 | ||
| 415 | config SOUND_MPU401 | 409 | config SOUND_MPU401 |
| 416 | tristate "MPU-401 support (NOT for SB16)" | 410 | tristate "MPU-401 support (NOT for SB16)" |
| 417 | depends on SOUND_OSS | ||
| 418 | ---help--- | 411 | ---help--- |
| 419 | Be careful with this question. The MPU401 interface is supported by | 412 | Be careful with this question. The MPU401 interface is supported by |
| 420 | all sound cards. However, some natively supported cards have their | 413 | all sound cards. However, some natively supported cards have their |
| @@ -430,7 +423,6 @@ config SOUND_MPU401 | |||
| 430 | 423 | ||
| 431 | config SOUND_PAS | 424 | config SOUND_PAS |
| 432 | tristate "ProAudioSpectrum 16 support" | 425 | tristate "ProAudioSpectrum 16 support" |
| 433 | depends on SOUND_OSS | ||
| 434 | ---help--- | 426 | ---help--- |
| 435 | Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio | 427 | Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio |
| 436 | 16 or Logitech SoundMan 16 sound card. Answer N if you have some | 428 | 16 or Logitech SoundMan 16 sound card. Answer N if you have some |
| @@ -452,7 +444,6 @@ config PAS_JOYSTICK | |||
| 452 | 444 | ||
| 453 | config SOUND_PSS | 445 | config SOUND_PSS |
| 454 | tristate "PSS (AD1848, ADSP-2115, ESC614) support" | 446 | tristate "PSS (AD1848, ADSP-2115, ESC614) support" |
| 455 | depends on SOUND_OSS | ||
| 456 | help | 447 | help |
| 457 | Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven | 448 | Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven |
| 458 | ADSP-16 or some other card based on the PSS chipset (AD1848 codec + | 449 | ADSP-16 or some other card based on the PSS chipset (AD1848 codec + |
| @@ -495,7 +486,6 @@ config PSS_BOOT_FILE | |||
| 495 | 486 | ||
| 496 | config SOUND_SB | 487 | config SOUND_SB |
| 497 | tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" | 488 | tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" |
| 498 | depends on SOUND_OSS | ||
| 499 | ---help--- | 489 | ---help--- |
| 500 | Answer Y if you have an original Sound Blaster card made by Creative | 490 | Answer Y if you have an original Sound Blaster card made by Creative |
| 501 | Labs or a 100% hardware compatible clone (like the Thunderboard or | 491 | Labs or a 100% hardware compatible clone (like the Thunderboard or |
| @@ -522,7 +512,6 @@ config SOUND_SB | |||
| 522 | 512 | ||
| 523 | config SOUND_YM3812 | 513 | config SOUND_YM3812 |
| 524 | tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" | 514 | tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" |
| 525 | depends on SOUND_OSS | ||
| 526 | ---help--- | 515 | ---help--- |
| 527 | Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). | 516 | Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). |
| 528 | Answering Y is usually a safe and recommended choice, however some | 517 | Answering Y is usually a safe and recommended choice, however some |
| @@ -538,7 +527,6 @@ config SOUND_YM3812 | |||
| 538 | 527 | ||
| 539 | config SOUND_UART6850 | 528 | config SOUND_UART6850 |
| 540 | tristate "6850 UART support" | 529 | tristate "6850 UART support" |
| 541 | depends on SOUND_OSS | ||
| 542 | help | 530 | help |
| 543 | This option enables support for MIDI interfaces based on the 6850 | 531 | This option enables support for MIDI interfaces based on the 6850 |
| 544 | UART chip. This interface is rarely found on sound cards. It's safe | 532 | UART chip. This interface is rarely found on sound cards. It's safe |
| @@ -549,7 +537,6 @@ config SOUND_UART6850 | |||
| 549 | 537 | ||
| 550 | config SOUND_AEDSP16 | 538 | config SOUND_AEDSP16 |
| 551 | tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" | 539 | tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" |
| 552 | depends on SOUND_OSS | ||
| 553 | ---help--- | 540 | ---help--- |
| 554 | Answer Y if you have a Gallant's Audio Excel DSP 16 card. This | 541 | Answer Y if you have a Gallant's Audio Excel DSP 16 card. This |
| 555 | driver supports Audio Excel DSP 16 but not the III nor PnP versions | 542 | driver supports Audio Excel DSP 16 but not the III nor PnP versions |
| @@ -630,14 +617,14 @@ endchoice | |||
| 630 | 617 | ||
| 631 | config SOUND_VIDC | 618 | config SOUND_VIDC |
| 632 | tristate "VIDC 16-bit sound" | 619 | tristate "VIDC 16-bit sound" |
| 633 | depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) && SOUND_OSS | 620 | depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) |
| 634 | help | 621 | help |
| 635 | 16-bit support for the VIDC onboard sound hardware found on Acorn | 622 | 16-bit support for the VIDC onboard sound hardware found on Acorn |
| 636 | machines. | 623 | machines. |
| 637 | 624 | ||
| 638 | config SOUND_WAVEARTIST | 625 | config SOUND_WAVEARTIST |
| 639 | tristate "Netwinder WaveArtist" | 626 | tristate "Netwinder WaveArtist" |
| 640 | depends on ARM && SOUND_OSS && ARCH_NETWINDER | 627 | depends on ARM && ARCH_NETWINDER |
| 641 | help | 628 | help |
| 642 | Say Y here to include support for the Rockwell WaveArtist sound | 629 | Say Y here to include support for the Rockwell WaveArtist sound |
| 643 | system. This driver is mainly for the NetWinder. | 630 | system. This driver is mainly for the NetWinder. |
| @@ -646,9 +633,11 @@ config SOUND_KAHLUA | |||
| 646 | tristate "XpressAudio Sound Blaster emulation" | 633 | tristate "XpressAudio Sound Blaster emulation" |
| 647 | depends on SOUND_SB | 634 | depends on SOUND_SB |
| 648 | 635 | ||
| 636 | endif # SOUND_OSS | ||
| 637 | |||
| 649 | config SOUND_SH_DAC_AUDIO | 638 | config SOUND_SH_DAC_AUDIO |
| 650 | tristate "SuperH DAC audio support" | 639 | tristate "SuperH DAC audio support" |
| 651 | depends on SOUND_PRIME && CPU_SH3 | 640 | depends on CPU_SH3 |
| 652 | 641 | ||
| 653 | config SOUND_SH_DAC_AUDIO_CHANNEL | 642 | config SOUND_SH_DAC_AUDIO_CHANNEL |
| 654 | int "DAC channel" | 643 | int "DAC channel" |
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index a003c0ea9303..95fc5c681755 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c | |||
| @@ -211,10 +211,6 @@ static int state_unit = -1; | |||
| 211 | static int irq_installed; | 211 | static int irq_installed; |
| 212 | #endif /* MODULE */ | 212 | #endif /* MODULE */ |
| 213 | 213 | ||
| 214 | /* software implemented recording volume! */ | ||
| 215 | uint software_input_volume = SW_INPUT_VOLUME_SCALE * SW_INPUT_VOLUME_DEFAULT; | ||
| 216 | EXPORT_SYMBOL(software_input_volume); | ||
| 217 | |||
| 218 | /* control over who can modify resources shared between play/record */ | 214 | /* control over who can modify resources shared between play/record */ |
| 219 | static mode_t shared_resource_owner; | 215 | static mode_t shared_resource_owner; |
| 220 | static int shared_resources_initialised; | 216 | static int shared_resources_initialised; |
| @@ -1188,7 +1184,7 @@ static struct { | |||
| 1188 | 1184 | ||
| 1189 | /* publish this function for use by low-level code, if required */ | 1185 | /* publish this function for use by low-level code, if required */ |
| 1190 | 1186 | ||
| 1191 | char *get_afmt_string(int afmt) | 1187 | static char *get_afmt_string(int afmt) |
| 1192 | { | 1188 | { |
| 1193 | switch(afmt) { | 1189 | switch(afmt) { |
| 1194 | case AFMT_MU_LAW: | 1190 | case AFMT_MU_LAW: |
| @@ -1551,4 +1547,3 @@ EXPORT_SYMBOL(dmasound_catchRadius); | |||
| 1551 | EXPORT_SYMBOL(dmasound_ulaw2dma8); | 1547 | EXPORT_SYMBOL(dmasound_ulaw2dma8); |
| 1552 | EXPORT_SYMBOL(dmasound_alaw2dma8); | 1548 | EXPORT_SYMBOL(dmasound_alaw2dma8); |
| 1553 | #endif | 1549 | #endif |
| 1554 | EXPORT_SYMBOL(get_afmt_string) ; | ||
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index 202e8103dc4d..06e9e88e4c05 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c | |||
| @@ -710,7 +710,7 @@ static MACHINE machAmiga = { | |||
| 710 | /*** Config & Setup **********************************************************/ | 710 | /*** Config & Setup **********************************************************/ |
| 711 | 711 | ||
| 712 | 712 | ||
| 713 | int __init dmasound_paula_init(void) | 713 | static int __init dmasound_paula_init(void) |
| 714 | { | 714 | { |
| 715 | int err; | 715 | int err; |
| 716 | 716 | ||
diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c index b3379dd7ca5e..1855b14d90c3 100644 --- a/sound/oss/dmasound/dmasound_q40.c +++ b/sound/oss/dmasound/dmasound_q40.c | |||
| @@ -611,7 +611,7 @@ static MACHINE machQ40 = { | |||
| 611 | /*** Config & Setup **********************************************************/ | 611 | /*** Config & Setup **********************************************************/ |
| 612 | 612 | ||
| 613 | 613 | ||
| 614 | int __init dmasound_q40_init(void) | 614 | static int __init dmasound_q40_init(void) |
| 615 | { | 615 | { |
| 616 | if (MACH_IS_Q40) { | 616 | if (MACH_IS_Q40) { |
| 617 | dmasound.mach = machQ40; | 617 | dmasound.mach = machQ40; |
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c index ba38d6200099..e4282d93a1aa 100644 --- a/sound/oss/msnd.c +++ b/sound/oss/msnd.c | |||
| @@ -20,8 +20,6 @@ | |||
| 20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
| 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 22 | * | 22 | * |
| 23 | * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $ | ||
| 24 | * | ||
| 25 | ********************************************************************/ | 23 | ********************************************************************/ |
| 26 | 24 | ||
| 27 | #include <linux/module.h> | 25 | #include <linux/module.h> |
diff --git a/sound/oss/msnd.h b/sound/oss/msnd.h index d0ca582c4583..61b3955481c5 100644 --- a/sound/oss/msnd.h +++ b/sound/oss/msnd.h | |||
| @@ -24,8 +24,6 @@ | |||
| 24 | * along with this program; if not, write to the Free Software | 24 | * along with this program; if not, write to the Free Software |
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 26 | * | 26 | * |
| 27 | * $Id: msnd.h,v 1.36 1999/03/21 17:05:42 andrewtv Exp $ | ||
| 28 | * | ||
| 29 | ********************************************************************/ | 27 | ********************************************************************/ |
| 30 | #ifndef __MSND_H | 28 | #ifndef __MSND_H |
| 31 | #define __MSND_H | 29 | #define __MSND_H |
diff --git a/sound/oss/msnd_classic.h b/sound/oss/msnd_classic.h index 7ffea5267f96..1a17dde2f650 100644 --- a/sound/oss/msnd_classic.h +++ b/sound/oss/msnd_classic.h | |||
| @@ -24,8 +24,6 @@ | |||
| 24 | * along with this program; if not, write to the Free Software | 24 | * along with this program; if not, write to the Free Software |
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 26 | * | 26 | * |
| 27 | * $Id: msnd_classic.h,v 1.10 1999/03/21 17:36:09 andrewtv Exp $ | ||
| 28 | * | ||
| 29 | ********************************************************************/ | 27 | ********************************************************************/ |
| 30 | #ifndef __MSND_CLASSIC_H | 28 | #ifndef __MSND_CLASSIC_H |
| 31 | #define __MSND_CLASSIC_H | 29 | #define __MSND_CLASSIC_H |
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index f1f49ebf752e..bf27e008f465 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c | |||
| @@ -29,13 +29,8 @@ | |||
| 29 | * along with this program; if not, write to the Free Software | 29 | * along with this program; if not, write to the Free Software |
| 30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 31 | * | 31 | * |
| 32 | * $Id: msnd_pinnacle.c,v 1.8 2000/12/30 00:33:21 sycamore Exp $ | ||
| 33 | * | ||
| 34 | * 12-3-2000 Modified IO port validation Steve Sycamore | 32 | * 12-3-2000 Modified IO port validation Steve Sycamore |
| 35 | * | 33 | * |
| 36 | * | ||
| 37 | * $$$: msnd_pinnacle.c,v 1.75 1999/03/21 16:50:09 andrewtv $$$ $ | ||
| 38 | * | ||
| 39 | ********************************************************************/ | 34 | ********************************************************************/ |
| 40 | 35 | ||
| 41 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
diff --git a/sound/oss/msnd_pinnacle.h b/sound/oss/msnd_pinnacle.h index cce911487004..c18d66cbbe3f 100644 --- a/sound/oss/msnd_pinnacle.h +++ b/sound/oss/msnd_pinnacle.h | |||
| @@ -24,8 +24,6 @@ | |||
| 24 | * along with this program; if not, write to the Free Software | 24 | * along with this program; if not, write to the Free Software |
| 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 26 | * | 26 | * |
| 27 | * $Id: msnd_pinnacle.h,v 1.11 1999/03/21 17:36:09 andrewtv Exp $ | ||
| 28 | * | ||
| 29 | ********************************************************************/ | 27 | ********************************************************************/ |
| 30 | #ifndef __MSND_PINNACLE_H | 28 | #ifndef __MSND_PINNACLE_H |
| 31 | #define __MSND_PINNACLE_H | 29 | #define __MSND_PINNACLE_H |
diff --git a/sound/parisc/Kconfig b/sound/parisc/Kconfig index a5a7f9d75d05..9b61d95010f0 100644 --- a/sound/parisc/Kconfig +++ b/sound/parisc/Kconfig | |||
| @@ -1,15 +1,20 @@ | |||
| 1 | # ALSA PA-RISC drivers | 1 | # ALSA PA-RISC drivers |
| 2 | 2 | ||
| 3 | menu "GSC devices" | 3 | menuconfig SND_GSC |
| 4 | depends on SND!=n && GSC | 4 | bool "GSC sound devices" |
| 5 | depends on GSC | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for GSC sound devices on PA-RISC architectures. | ||
| 9 | |||
| 10 | if SND_GSC | ||
| 5 | 11 | ||
| 6 | config SND_HARMONY | 12 | config SND_HARMONY |
| 7 | tristate "Harmony/Vivace sound chip" | 13 | tristate "Harmony/Vivace sound chip" |
| 8 | depends on SND | ||
| 9 | select SND_PCM | 14 | select SND_PCM |
| 10 | help | 15 | help |
| 11 | Say 'Y' or 'M' to include support for the Harmony/Vivace sound | 16 | Say 'Y' or 'M' to include support for the Harmony/Vivace sound |
| 12 | chip found in most GSC-based PA-RISC workstations. It's frequently | 17 | chip found in most GSC-based PA-RISC workstations. It's frequently |
| 13 | provided as part of the Lasi multi-function IC. | 18 | provided as part of the Lasi multi-function IC. |
| 14 | 19 | ||
| 15 | endmenu | 20 | endif # SND_GSC |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7e4742109572..8fe5dac39428 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
| @@ -1,11 +1,16 @@ | |||
| 1 | # ALSA PCI drivers | 1 | # ALSA PCI drivers |
| 2 | 2 | ||
| 3 | menu "PCI devices" | 3 | menuconfig SND_PCI |
| 4 | depends on SND!=n && PCI | 4 | bool "PCI sound devices" |
| 5 | depends on PCI | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices connected via the PCI bus. | ||
| 9 | |||
| 10 | if SND_PCI | ||
| 5 | 11 | ||
| 6 | config SND_AD1889 | 12 | config SND_AD1889 |
| 7 | tristate "Analog Devices AD1889" | 13 | tristate "Analog Devices AD1889" |
| 8 | depends on SND | ||
| 9 | select SND_AC97_CODEC | 14 | select SND_AC97_CODEC |
| 10 | help | 15 | help |
| 11 | Say Y here to include support for the integrated AC97 sound | 16 | Say Y here to include support for the integrated AC97 sound |
| @@ -17,7 +22,6 @@ config SND_AD1889 | |||
| 17 | 22 | ||
| 18 | config SND_ALS300 | 23 | config SND_ALS300 |
| 19 | tristate "Avance Logic ALS300/ALS300+" | 24 | tristate "Avance Logic ALS300/ALS300+" |
| 20 | depends on SND | ||
| 21 | select SND_PCM | 25 | select SND_PCM |
| 22 | select SND_AC97_CODEC | 26 | select SND_AC97_CODEC |
| 23 | select SND_OPL3_LIB | 27 | select SND_OPL3_LIB |
| @@ -29,7 +33,7 @@ config SND_ALS300 | |||
| 29 | 33 | ||
| 30 | config SND_ALS4000 | 34 | config SND_ALS4000 |
| 31 | tristate "Avance Logic ALS4000" | 35 | tristate "Avance Logic ALS4000" |
| 32 | depends on SND && ISA_DMA_API | 36 | depends on ISA_DMA_API |
| 33 | select SND_OPL3_LIB | 37 | select SND_OPL3_LIB |
| 34 | select SND_MPU401_UART | 38 | select SND_MPU401_UART |
| 35 | select SND_PCM | 39 | select SND_PCM |
| @@ -43,7 +47,6 @@ config SND_ALS4000 | |||
| 43 | 47 | ||
| 44 | config SND_ALI5451 | 48 | config SND_ALI5451 |
| 45 | tristate "ALi M5451 PCI Audio Controller" | 49 | tristate "ALi M5451 PCI Audio Controller" |
| 46 | depends on SND | ||
| 47 | select SND_MPU401_UART | 50 | select SND_MPU401_UART |
| 48 | select SND_AC97_CODEC | 51 | select SND_AC97_CODEC |
| 49 | help | 52 | help |
| @@ -57,7 +60,6 @@ config SND_ALI5451 | |||
| 57 | 60 | ||
| 58 | config SND_ATIIXP | 61 | config SND_ATIIXP |
| 59 | tristate "ATI IXP AC97 Controller" | 62 | tristate "ATI IXP AC97 Controller" |
| 60 | depends on SND | ||
| 61 | select SND_AC97_CODEC | 63 | select SND_AC97_CODEC |
| 62 | help | 64 | help |
| 63 | Say Y here to include support for the integrated AC97 sound | 65 | Say Y here to include support for the integrated AC97 sound |
| @@ -69,7 +71,6 @@ config SND_ATIIXP | |||
| 69 | 71 | ||
| 70 | config SND_ATIIXP_MODEM | 72 | config SND_ATIIXP_MODEM |
| 71 | tristate "ATI IXP Modem" | 73 | tristate "ATI IXP Modem" |
| 72 | depends on SND | ||
| 73 | select SND_AC97_CODEC | 74 | select SND_AC97_CODEC |
| 74 | help | 75 | help |
| 75 | Say Y here to include support for the integrated MC97 modem on | 76 | Say Y here to include support for the integrated MC97 modem on |
| @@ -80,7 +81,6 @@ config SND_ATIIXP_MODEM | |||
| 80 | 81 | ||
| 81 | config SND_AU8810 | 82 | config SND_AU8810 |
| 82 | tristate "Aureal Advantage" | 83 | tristate "Aureal Advantage" |
| 83 | depends on SND | ||
| 84 | select SND_MPU401_UART | 84 | select SND_MPU401_UART |
| 85 | select SND_AC97_CODEC | 85 | select SND_AC97_CODEC |
| 86 | help | 86 | help |
| @@ -95,7 +95,6 @@ config SND_AU8810 | |||
| 95 | 95 | ||
| 96 | config SND_AU8820 | 96 | config SND_AU8820 |
| 97 | tristate "Aureal Vortex" | 97 | tristate "Aureal Vortex" |
| 98 | depends on SND | ||
| 99 | select SND_MPU401_UART | 98 | select SND_MPU401_UART |
| 100 | select SND_AC97_CODEC | 99 | select SND_AC97_CODEC |
| 101 | help | 100 | help |
| @@ -109,7 +108,6 @@ config SND_AU8820 | |||
| 109 | 108 | ||
| 110 | config SND_AU8830 | 109 | config SND_AU8830 |
| 111 | tristate "Aureal Vortex 2" | 110 | tristate "Aureal Vortex 2" |
| 112 | depends on SND | ||
| 113 | select SND_MPU401_UART | 111 | select SND_MPU401_UART |
| 114 | select SND_AC97_CODEC | 112 | select SND_AC97_CODEC |
| 115 | help | 113 | help |
| @@ -124,7 +122,6 @@ config SND_AU8830 | |||
| 124 | 122 | ||
| 125 | config SND_AW2 | 123 | config SND_AW2 |
| 126 | tristate "Emagic Audiowerk 2" | 124 | tristate "Emagic Audiowerk 2" |
| 127 | depends on SND | ||
| 128 | help | 125 | help |
| 129 | Say Y here to include support for Emagic Audiowerk 2 soundcards. | 126 | Say Y here to include support for Emagic Audiowerk 2 soundcards. |
| 130 | 127 | ||
| @@ -139,7 +136,7 @@ config SND_AW2 | |||
| 139 | 136 | ||
| 140 | config SND_AZT3328 | 137 | config SND_AZT3328 |
| 141 | tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" | 138 | tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" |
| 142 | depends on SND && EXPERIMENTAL | 139 | depends on EXPERIMENTAL |
| 143 | select SND_OPL3_LIB | 140 | select SND_OPL3_LIB |
| 144 | select SND_MPU401_UART | 141 | select SND_MPU401_UART |
| 145 | select SND_PCM | 142 | select SND_PCM |
| @@ -152,7 +149,6 @@ config SND_AZT3328 | |||
| 152 | 149 | ||
| 153 | config SND_BT87X | 150 | config SND_BT87X |
| 154 | tristate "Bt87x Audio Capture" | 151 | tristate "Bt87x Audio Capture" |
| 155 | depends on SND | ||
| 156 | select SND_PCM | 152 | select SND_PCM |
| 157 | help | 153 | help |
| 158 | If you want to record audio from TV cards based on | 154 | If you want to record audio from TV cards based on |
| @@ -174,7 +170,6 @@ config SND_BT87X_OVERCLOCK | |||
| 174 | 170 | ||
| 175 | config SND_CA0106 | 171 | config SND_CA0106 |
| 176 | tristate "SB Audigy LS / Live 24bit" | 172 | tristate "SB Audigy LS / Live 24bit" |
| 177 | depends on SND | ||
| 178 | select SND_AC97_CODEC | 173 | select SND_AC97_CODEC |
| 179 | select SND_RAWMIDI | 174 | select SND_RAWMIDI |
| 180 | select SND_VMASTER | 175 | select SND_VMASTER |
| @@ -187,7 +182,6 @@ config SND_CA0106 | |||
| 187 | 182 | ||
| 188 | config SND_CMIPCI | 183 | config SND_CMIPCI |
| 189 | tristate "C-Media 8338, 8738, 8768, 8770" | 184 | tristate "C-Media 8338, 8738, 8768, 8770" |
| 190 | depends on SND | ||
| 191 | select SND_OPL3_LIB | 185 | select SND_OPL3_LIB |
| 192 | select SND_MPU401_UART | 186 | select SND_MPU401_UART |
| 193 | select SND_PCM | 187 | select SND_PCM |
| @@ -201,13 +195,11 @@ config SND_CMIPCI | |||
| 201 | 195 | ||
| 202 | config SND_OXYGEN_LIB | 196 | config SND_OXYGEN_LIB |
| 203 | tristate | 197 | tristate |
| 204 | depends on SND | ||
| 205 | select SND_PCM | 198 | select SND_PCM |
| 206 | select SND_MPU401_UART | 199 | select SND_MPU401_UART |
| 207 | 200 | ||
| 208 | config SND_OXYGEN | 201 | config SND_OXYGEN |
| 209 | tristate "C-Media 8788 (Oxygen)" | 202 | tristate "C-Media 8788 (Oxygen)" |
| 210 | depends on SND | ||
| 211 | select SND_OXYGEN_LIB | 203 | select SND_OXYGEN_LIB |
| 212 | help | 204 | help |
| 213 | Say Y here to include support for sound cards based on the | 205 | Say Y here to include support for sound cards based on the |
| @@ -225,7 +217,6 @@ config SND_OXYGEN | |||
| 225 | 217 | ||
| 226 | config SND_CS4281 | 218 | config SND_CS4281 |
| 227 | tristate "Cirrus Logic (Sound Fusion) CS4281" | 219 | tristate "Cirrus Logic (Sound Fusion) CS4281" |
| 228 | depends on SND | ||
| 229 | select SND_OPL3_LIB | 220 | select SND_OPL3_LIB |
| 230 | select SND_RAWMIDI | 221 | select SND_RAWMIDI |
| 231 | select SND_AC97_CODEC | 222 | select SND_AC97_CODEC |
| @@ -237,7 +228,6 @@ config SND_CS4281 | |||
| 237 | 228 | ||
| 238 | config SND_CS46XX | 229 | config SND_CS46XX |
| 239 | tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" | 230 | tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" |
| 240 | depends on SND | ||
| 241 | select SND_RAWMIDI | 231 | select SND_RAWMIDI |
| 242 | select SND_AC97_CODEC | 232 | select SND_AC97_CODEC |
| 243 | help | 233 | help |
| @@ -258,7 +248,7 @@ config SND_CS46XX_NEW_DSP | |||
| 258 | 248 | ||
| 259 | config SND_CS5530 | 249 | config SND_CS5530 |
| 260 | tristate "CS5530 Audio" | 250 | tristate "CS5530 Audio" |
| 261 | depends on SND && ISA_DMA_API | 251 | depends on ISA_DMA_API |
| 262 | select SND_SB16_DSP | 252 | select SND_SB16_DSP |
| 263 | help | 253 | help |
| 264 | Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips. | 254 | Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips. |
| @@ -268,7 +258,7 @@ config SND_CS5530 | |||
| 268 | 258 | ||
| 269 | config SND_CS5535AUDIO | 259 | config SND_CS5535AUDIO |
| 270 | tristate "CS5535/CS5536 Audio" | 260 | tristate "CS5535/CS5536 Audio" |
| 271 | depends on SND && X86 && !X86_64 | 261 | depends on X86 && !X86_64 |
| 272 | select SND_PCM | 262 | select SND_PCM |
| 273 | select SND_AC97_CODEC | 263 | select SND_AC97_CODEC |
| 274 | help | 264 | help |
| @@ -286,7 +276,6 @@ config SND_CS5535AUDIO | |||
| 286 | 276 | ||
| 287 | config SND_DARLA20 | 277 | config SND_DARLA20 |
| 288 | tristate "(Echoaudio) Darla20" | 278 | tristate "(Echoaudio) Darla20" |
| 289 | depends on SND | ||
| 290 | select FW_LOADER | 279 | select FW_LOADER |
| 291 | select SND_PCM | 280 | select SND_PCM |
| 292 | help | 281 | help |
| @@ -297,7 +286,6 @@ config SND_DARLA20 | |||
| 297 | 286 | ||
| 298 | config SND_GINA20 | 287 | config SND_GINA20 |
| 299 | tristate "(Echoaudio) Gina20" | 288 | tristate "(Echoaudio) Gina20" |
| 300 | depends on SND | ||
| 301 | select FW_LOADER | 289 | select FW_LOADER |
| 302 | select SND_PCM | 290 | select SND_PCM |
| 303 | help | 291 | help |
| @@ -308,7 +296,6 @@ config SND_GINA20 | |||
| 308 | 296 | ||
| 309 | config SND_LAYLA20 | 297 | config SND_LAYLA20 |
| 310 | tristate "(Echoaudio) Layla20" | 298 | tristate "(Echoaudio) Layla20" |
| 311 | depends on SND | ||
| 312 | select FW_LOADER | 299 | select FW_LOADER |
| 313 | select SND_RAWMIDI | 300 | select SND_RAWMIDI |
| 314 | select SND_PCM | 301 | select SND_PCM |
| @@ -320,7 +307,6 @@ config SND_LAYLA20 | |||
| 320 | 307 | ||
| 321 | config SND_DARLA24 | 308 | config SND_DARLA24 |
| 322 | tristate "(Echoaudio) Darla24" | 309 | tristate "(Echoaudio) Darla24" |
| 323 | depends on SND | ||
| 324 | select FW_LOADER | 310 | select FW_LOADER |
| 325 | select SND_PCM | 311 | select SND_PCM |
| 326 | help | 312 | help |
| @@ -331,7 +317,6 @@ config SND_DARLA24 | |||
| 331 | 317 | ||
| 332 | config SND_GINA24 | 318 | config SND_GINA24 |
| 333 | tristate "(Echoaudio) Gina24" | 319 | tristate "(Echoaudio) Gina24" |
| 334 | depends on SND | ||
| 335 | select FW_LOADER | 320 | select FW_LOADER |
| 336 | select SND_PCM | 321 | select SND_PCM |
| 337 | help | 322 | help |
| @@ -342,7 +327,6 @@ config SND_GINA24 | |||
| 342 | 327 | ||
| 343 | config SND_LAYLA24 | 328 | config SND_LAYLA24 |
| 344 | tristate "(Echoaudio) Layla24" | 329 | tristate "(Echoaudio) Layla24" |
| 345 | depends on SND | ||
| 346 | select FW_LOADER | 330 | select FW_LOADER |
| 347 | select SND_RAWMIDI | 331 | select SND_RAWMIDI |
| 348 | select SND_PCM | 332 | select SND_PCM |
| @@ -354,7 +338,6 @@ config SND_LAYLA24 | |||
| 354 | 338 | ||
| 355 | config SND_MONA | 339 | config SND_MONA |
| 356 | tristate "(Echoaudio) Mona" | 340 | tristate "(Echoaudio) Mona" |
| 357 | depends on SND | ||
| 358 | select FW_LOADER | 341 | select FW_LOADER |
| 359 | select SND_RAWMIDI | 342 | select SND_RAWMIDI |
| 360 | select SND_PCM | 343 | select SND_PCM |
| @@ -366,7 +349,6 @@ config SND_MONA | |||
| 366 | 349 | ||
| 367 | config SND_MIA | 350 | config SND_MIA |
| 368 | tristate "(Echoaudio) Mia" | 351 | tristate "(Echoaudio) Mia" |
| 369 | depends on SND | ||
| 370 | select FW_LOADER | 352 | select FW_LOADER |
| 371 | select SND_RAWMIDI | 353 | select SND_RAWMIDI |
| 372 | select SND_PCM | 354 | select SND_PCM |
| @@ -378,7 +360,6 @@ config SND_MIA | |||
| 378 | 360 | ||
| 379 | config SND_ECHO3G | 361 | config SND_ECHO3G |
| 380 | tristate "(Echoaudio) 3G cards" | 362 | tristate "(Echoaudio) 3G cards" |
| 381 | depends on SND | ||
| 382 | select FW_LOADER | 363 | select FW_LOADER |
| 383 | select SND_RAWMIDI | 364 | select SND_RAWMIDI |
| 384 | select SND_PCM | 365 | select SND_PCM |
| @@ -390,7 +371,6 @@ config SND_ECHO3G | |||
| 390 | 371 | ||
| 391 | config SND_INDIGO | 372 | config SND_INDIGO |
| 392 | tristate "(Echoaudio) Indigo" | 373 | tristate "(Echoaudio) Indigo" |
| 393 | depends on SND | ||
| 394 | select FW_LOADER | 374 | select FW_LOADER |
| 395 | select SND_PCM | 375 | select SND_PCM |
| 396 | help | 376 | help |
| @@ -401,7 +381,6 @@ config SND_INDIGO | |||
| 401 | 381 | ||
| 402 | config SND_INDIGOIO | 382 | config SND_INDIGOIO |
| 403 | tristate "(Echoaudio) Indigo IO" | 383 | tristate "(Echoaudio) Indigo IO" |
| 404 | depends on SND | ||
| 405 | select FW_LOADER | 384 | select FW_LOADER |
| 406 | select SND_PCM | 385 | select SND_PCM |
| 407 | help | 386 | help |
| @@ -412,7 +391,6 @@ config SND_INDIGOIO | |||
| 412 | 391 | ||
| 413 | config SND_INDIGODJ | 392 | config SND_INDIGODJ |
| 414 | tristate "(Echoaudio) Indigo DJ" | 393 | tristate "(Echoaudio) Indigo DJ" |
| 415 | depends on SND | ||
| 416 | select FW_LOADER | 394 | select FW_LOADER |
| 417 | select SND_PCM | 395 | select SND_PCM |
| 418 | help | 396 | help |
| @@ -423,7 +401,6 @@ config SND_INDIGODJ | |||
| 423 | 401 | ||
| 424 | config SND_EMU10K1 | 402 | config SND_EMU10K1 |
| 425 | tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" | 403 | tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" |
| 426 | depends on SND | ||
| 427 | select FW_LOADER | 404 | select FW_LOADER |
| 428 | select SND_HWDEP | 405 | select SND_HWDEP |
| 429 | select SND_RAWMIDI | 406 | select SND_RAWMIDI |
| @@ -441,7 +418,6 @@ config SND_EMU10K1 | |||
| 441 | 418 | ||
| 442 | config SND_EMU10K1X | 419 | config SND_EMU10K1X |
| 443 | tristate "Emu10k1X (Dell OEM Version)" | 420 | tristate "Emu10k1X (Dell OEM Version)" |
| 444 | depends on SND | ||
| 445 | select SND_AC97_CODEC | 421 | select SND_AC97_CODEC |
| 446 | select SND_RAWMIDI | 422 | select SND_RAWMIDI |
| 447 | help | 423 | help |
| @@ -453,7 +429,6 @@ config SND_EMU10K1X | |||
| 453 | 429 | ||
| 454 | config SND_ENS1370 | 430 | config SND_ENS1370 |
| 455 | tristate "(Creative) Ensoniq AudioPCI 1370" | 431 | tristate "(Creative) Ensoniq AudioPCI 1370" |
| 456 | depends on SND | ||
| 457 | select SND_RAWMIDI | 432 | select SND_RAWMIDI |
| 458 | select SND_PCM | 433 | select SND_PCM |
| 459 | help | 434 | help |
| @@ -464,7 +439,6 @@ config SND_ENS1370 | |||
| 464 | 439 | ||
| 465 | config SND_ENS1371 | 440 | config SND_ENS1371 |
| 466 | tristate "(Creative) Ensoniq AudioPCI 1371/1373" | 441 | tristate "(Creative) Ensoniq AudioPCI 1371/1373" |
| 467 | depends on SND | ||
| 468 | select SND_RAWMIDI | 442 | select SND_RAWMIDI |
| 469 | select SND_AC97_CODEC | 443 | select SND_AC97_CODEC |
| 470 | help | 444 | help |
| @@ -476,7 +450,6 @@ config SND_ENS1371 | |||
| 476 | 450 | ||
| 477 | config SND_ES1938 | 451 | config SND_ES1938 |
| 478 | tristate "ESS ES1938/1946/1969 (Solo-1)" | 452 | tristate "ESS ES1938/1946/1969 (Solo-1)" |
| 479 | depends on SND | ||
| 480 | select SND_OPL3_LIB | 453 | select SND_OPL3_LIB |
| 481 | select SND_MPU401_UART | 454 | select SND_MPU401_UART |
| 482 | select SND_AC97_CODEC | 455 | select SND_AC97_CODEC |
| @@ -489,7 +462,6 @@ config SND_ES1938 | |||
| 489 | 462 | ||
| 490 | config SND_ES1968 | 463 | config SND_ES1968 |
| 491 | tristate "ESS ES1968/1978 (Maestro-1/2/2E)" | 464 | tristate "ESS ES1968/1978 (Maestro-1/2/2E)" |
| 492 | depends on SND | ||
| 493 | select SND_MPU401_UART | 465 | select SND_MPU401_UART |
| 494 | select SND_AC97_CODEC | 466 | select SND_AC97_CODEC |
| 495 | help | 467 | help |
| @@ -501,7 +473,6 @@ config SND_ES1968 | |||
| 501 | 473 | ||
| 502 | config SND_FM801 | 474 | config SND_FM801 |
| 503 | tristate "ForteMedia FM801" | 475 | tristate "ForteMedia FM801" |
| 504 | depends on SND | ||
| 505 | select SND_OPL3_LIB | 476 | select SND_OPL3_LIB |
| 506 | select SND_MPU401_UART | 477 | select SND_MPU401_UART |
| 507 | select SND_AC97_CODEC | 478 | select SND_AC97_CODEC |
| @@ -528,7 +499,6 @@ config SND_FM801_TEA575X | |||
| 528 | 499 | ||
| 529 | config SND_HDA_INTEL | 500 | config SND_HDA_INTEL |
| 530 | tristate "Intel HD Audio" | 501 | tristate "Intel HD Audio" |
| 531 | depends on SND | ||
| 532 | select SND_PCM | 502 | select SND_PCM |
| 533 | select SND_VMASTER | 503 | select SND_VMASTER |
| 534 | help | 504 | help |
| @@ -637,7 +607,6 @@ config SND_HDA_POWER_SAVE_DEFAULT | |||
| 637 | 607 | ||
| 638 | config SND_HDSP | 608 | config SND_HDSP |
| 639 | tristate "RME Hammerfall DSP Audio" | 609 | tristate "RME Hammerfall DSP Audio" |
| 640 | depends on SND | ||
| 641 | select SND_HWDEP | 610 | select SND_HWDEP |
| 642 | select SND_RAWMIDI | 611 | select SND_RAWMIDI |
| 643 | select SND_PCM | 612 | select SND_PCM |
| @@ -650,7 +619,6 @@ config SND_HDSP | |||
| 650 | 619 | ||
| 651 | config SND_HDSPM | 620 | config SND_HDSPM |
| 652 | tristate "RME Hammerfall DSP MADI" | 621 | tristate "RME Hammerfall DSP MADI" |
| 653 | depends on SND | ||
| 654 | select SND_HWDEP | 622 | select SND_HWDEP |
| 655 | select SND_RAWMIDI | 623 | select SND_RAWMIDI |
| 656 | select SND_PCM | 624 | select SND_PCM |
| @@ -663,7 +631,6 @@ config SND_HDSPM | |||
| 663 | 631 | ||
| 664 | config SND_HIFIER | 632 | config SND_HIFIER |
| 665 | tristate "TempoTec HiFier Fantasia" | 633 | tristate "TempoTec HiFier Fantasia" |
| 666 | depends on SND | ||
| 667 | select SND_OXYGEN_LIB | 634 | select SND_OXYGEN_LIB |
| 668 | help | 635 | help |
| 669 | Say Y here to include support for the MediaTek/TempoTec HiFier | 636 | Say Y here to include support for the MediaTek/TempoTec HiFier |
| @@ -674,7 +641,6 @@ config SND_HIFIER | |||
| 674 | 641 | ||
| 675 | config SND_ICE1712 | 642 | config SND_ICE1712 |
| 676 | tristate "ICEnsemble ICE1712 (Envy24)" | 643 | tristate "ICEnsemble ICE1712 (Envy24)" |
| 677 | depends on SND | ||
| 678 | select SND_MPU401_UART | 644 | select SND_MPU401_UART |
| 679 | select SND_AC97_CODEC | 645 | select SND_AC97_CODEC |
| 680 | help | 646 | help |
| @@ -691,8 +657,7 @@ config SND_ICE1712 | |||
| 691 | 657 | ||
| 692 | config SND_ICE1724 | 658 | config SND_ICE1724 |
| 693 | tristate "ICE/VT1724/1720 (Envy24HT/PT)" | 659 | tristate "ICE/VT1724/1720 (Envy24HT/PT)" |
| 694 | depends on SND | 660 | select SND_RAWMIDI |
| 695 | select SND_MPU401_UART | ||
| 696 | select SND_AC97_CODEC | 661 | select SND_AC97_CODEC |
| 697 | select SND_VMASTER | 662 | select SND_VMASTER |
| 698 | help | 663 | help |
| @@ -709,7 +674,6 @@ config SND_ICE1724 | |||
| 709 | 674 | ||
| 710 | config SND_INTEL8X0 | 675 | config SND_INTEL8X0 |
| 711 | tristate "Intel/SiS/nVidia/AMD/ALi AC97 Controller" | 676 | tristate "Intel/SiS/nVidia/AMD/ALi AC97 Controller" |
| 712 | depends on SND | ||
| 713 | select SND_AC97_CODEC | 677 | select SND_AC97_CODEC |
| 714 | help | 678 | help |
| 715 | Say Y here to include support for the integrated AC97 sound | 679 | Say Y here to include support for the integrated AC97 sound |
| @@ -722,7 +686,6 @@ config SND_INTEL8X0 | |||
| 722 | 686 | ||
| 723 | config SND_INTEL8X0M | 687 | config SND_INTEL8X0M |
| 724 | tristate "Intel/SiS/nVidia/AMD MC97 Modem" | 688 | tristate "Intel/SiS/nVidia/AMD MC97 Modem" |
| 725 | depends on SND | ||
| 726 | select SND_AC97_CODEC | 689 | select SND_AC97_CODEC |
| 727 | help | 690 | help |
| 728 | Say Y here to include support for the integrated MC97 modem on | 691 | Say Y here to include support for the integrated MC97 modem on |
| @@ -733,7 +696,6 @@ config SND_INTEL8X0M | |||
| 733 | 696 | ||
| 734 | config SND_KORG1212 | 697 | config SND_KORG1212 |
| 735 | tristate "Korg 1212 IO" | 698 | tristate "Korg 1212 IO" |
| 736 | depends on SND | ||
| 737 | select FW_LOADER if !SND_KORG1212_FIRMWARE_IN_KERNEL | 699 | select FW_LOADER if !SND_KORG1212_FIRMWARE_IN_KERNEL |
| 738 | select SND_PCM | 700 | select SND_PCM |
| 739 | help | 701 | help |
| @@ -753,7 +715,6 @@ config SND_KORG1212_FIRMWARE_IN_KERNEL | |||
| 753 | 715 | ||
| 754 | config SND_MAESTRO3 | 716 | config SND_MAESTRO3 |
| 755 | tristate "ESS Allegro/Maestro3" | 717 | tristate "ESS Allegro/Maestro3" |
| 756 | depends on SND | ||
| 757 | select FW_LOADER if !SND_MAESTRO3_FIRMWARE_IN_KERNEL | 718 | select FW_LOADER if !SND_MAESTRO3_FIRMWARE_IN_KERNEL |
| 758 | select SND_AC97_CODEC | 719 | select SND_AC97_CODEC |
| 759 | help | 720 | help |
| @@ -774,7 +735,6 @@ config SND_MAESTRO3_FIRMWARE_IN_KERNEL | |||
| 774 | 735 | ||
| 775 | config SND_MIXART | 736 | config SND_MIXART |
| 776 | tristate "Digigram miXart" | 737 | tristate "Digigram miXart" |
| 777 | depends on SND | ||
| 778 | select SND_HWDEP | 738 | select SND_HWDEP |
| 779 | select SND_PCM | 739 | select SND_PCM |
| 780 | help | 740 | help |
| @@ -786,7 +746,6 @@ config SND_MIXART | |||
| 786 | 746 | ||
| 787 | config SND_NM256 | 747 | config SND_NM256 |
| 788 | tristate "NeoMagic NM256AV/ZX" | 748 | tristate "NeoMagic NM256AV/ZX" |
| 789 | depends on SND | ||
| 790 | select SND_AC97_CODEC | 749 | select SND_AC97_CODEC |
| 791 | help | 750 | help |
| 792 | Say Y here to include support for NeoMagic NM256AV/ZX chips. | 751 | Say Y here to include support for NeoMagic NM256AV/ZX chips. |
| @@ -796,7 +755,6 @@ config SND_NM256 | |||
| 796 | 755 | ||
| 797 | config SND_PCXHR | 756 | config SND_PCXHR |
| 798 | tristate "Digigram PCXHR" | 757 | tristate "Digigram PCXHR" |
| 799 | depends on SND | ||
| 800 | select SND_PCM | 758 | select SND_PCM |
| 801 | select SND_HWDEP | 759 | select SND_HWDEP |
| 802 | help | 760 | help |
| @@ -807,7 +765,6 @@ config SND_PCXHR | |||
| 807 | 765 | ||
| 808 | config SND_RIPTIDE | 766 | config SND_RIPTIDE |
| 809 | tristate "Conexant Riptide" | 767 | tristate "Conexant Riptide" |
| 810 | depends on SND | ||
| 811 | select FW_LOADER | 768 | select FW_LOADER |
| 812 | select SND_OPL3_LIB | 769 | select SND_OPL3_LIB |
| 813 | select SND_MPU401_UART | 770 | select SND_MPU401_UART |
| @@ -820,7 +777,6 @@ config SND_RIPTIDE | |||
| 820 | 777 | ||
| 821 | config SND_RME32 | 778 | config SND_RME32 |
| 822 | tristate "RME Digi32, 32/8, 32 PRO" | 779 | tristate "RME Digi32, 32/8, 32 PRO" |
| 823 | depends on SND | ||
| 824 | select SND_PCM | 780 | select SND_PCM |
| 825 | help | 781 | help |
| 826 | Say Y to include support for RME Digi32, Digi32 PRO and | 782 | Say Y to include support for RME Digi32, Digi32 PRO and |
| @@ -832,7 +788,6 @@ config SND_RME32 | |||
| 832 | 788 | ||
| 833 | config SND_RME96 | 789 | config SND_RME96 |
| 834 | tristate "RME Digi96, 96/8, 96/8 PRO" | 790 | tristate "RME Digi96, 96/8, 96/8 PRO" |
| 835 | depends on SND | ||
| 836 | select SND_PCM | 791 | select SND_PCM |
| 837 | help | 792 | help |
| 838 | Say Y here to include support for RME Digi96, Digi96/8 and | 793 | Say Y here to include support for RME Digi96, Digi96/8 and |
| @@ -843,7 +798,6 @@ config SND_RME96 | |||
| 843 | 798 | ||
| 844 | config SND_RME9652 | 799 | config SND_RME9652 |
| 845 | tristate "RME Digi9652 (Hammerfall)" | 800 | tristate "RME Digi9652 (Hammerfall)" |
| 846 | depends on SND | ||
| 847 | select SND_PCM | 801 | select SND_PCM |
| 848 | help | 802 | help |
| 849 | Say Y here to include support for RME Hammerfall (RME | 803 | Say Y here to include support for RME Hammerfall (RME |
| @@ -854,7 +808,7 @@ config SND_RME9652 | |||
| 854 | 808 | ||
| 855 | config SND_SIS7019 | 809 | config SND_SIS7019 |
| 856 | tristate "SiS 7019 Audio Accelerator" | 810 | tristate "SiS 7019 Audio Accelerator" |
| 857 | depends on SND && X86 && !X86_64 | 811 | depends on X86 && !X86_64 |
| 858 | select SND_AC97_CODEC | 812 | select SND_AC97_CODEC |
| 859 | help | 813 | help |
| 860 | Say Y here to include support for the SiS 7019 Audio Accelerator. | 814 | Say Y here to include support for the SiS 7019 Audio Accelerator. |
| @@ -864,7 +818,6 @@ config SND_SIS7019 | |||
| 864 | 818 | ||
| 865 | config SND_SONICVIBES | 819 | config SND_SONICVIBES |
| 866 | tristate "S3 SonicVibes" | 820 | tristate "S3 SonicVibes" |
| 867 | depends on SND | ||
| 868 | select SND_OPL3_LIB | 821 | select SND_OPL3_LIB |
| 869 | select SND_MPU401_UART | 822 | select SND_MPU401_UART |
| 870 | select SND_AC97_CODEC | 823 | select SND_AC97_CODEC |
| @@ -877,7 +830,6 @@ config SND_SONICVIBES | |||
| 877 | 830 | ||
| 878 | config SND_TRIDENT | 831 | config SND_TRIDENT |
| 879 | tristate "Trident 4D-Wave DX/NX; SiS 7018" | 832 | tristate "Trident 4D-Wave DX/NX; SiS 7018" |
| 880 | depends on SND | ||
| 881 | select SND_MPU401_UART | 833 | select SND_MPU401_UART |
| 882 | select SND_AC97_CODEC | 834 | select SND_AC97_CODEC |
| 883 | help | 835 | help |
| @@ -889,7 +841,6 @@ config SND_TRIDENT | |||
| 889 | 841 | ||
| 890 | config SND_VIA82XX | 842 | config SND_VIA82XX |
| 891 | tristate "VIA 82C686A/B, 8233/8235 AC97 Controller" | 843 | tristate "VIA 82C686A/B, 8233/8235 AC97 Controller" |
| 892 | depends on SND | ||
| 893 | select SND_MPU401_UART | 844 | select SND_MPU401_UART |
| 894 | select SND_AC97_CODEC | 845 | select SND_AC97_CODEC |
| 895 | help | 846 | help |
| @@ -901,7 +852,6 @@ config SND_VIA82XX | |||
| 901 | 852 | ||
| 902 | config SND_VIA82XX_MODEM | 853 | config SND_VIA82XX_MODEM |
| 903 | tristate "VIA 82C686A/B, 8233 based Modems" | 854 | tristate "VIA 82C686A/B, 8233 based Modems" |
| 904 | depends on SND | ||
| 905 | select SND_AC97_CODEC | 855 | select SND_AC97_CODEC |
| 906 | help | 856 | help |
| 907 | Say Y here to include support for the integrated MC97 modem on | 857 | Say Y here to include support for the integrated MC97 modem on |
| @@ -912,7 +862,6 @@ config SND_VIA82XX_MODEM | |||
| 912 | 862 | ||
| 913 | config SND_VIRTUOSO | 863 | config SND_VIRTUOSO |
| 914 | tristate "Asus Virtuoso 100/200 (Xonar)" | 864 | tristate "Asus Virtuoso 100/200 (Xonar)" |
| 915 | depends on SND | ||
| 916 | select SND_OXYGEN_LIB | 865 | select SND_OXYGEN_LIB |
| 917 | help | 866 | help |
| 918 | Say Y here to include support for sound cards based on the | 867 | Say Y here to include support for sound cards based on the |
| @@ -923,7 +872,6 @@ config SND_VIRTUOSO | |||
| 923 | 872 | ||
| 924 | config SND_VX222 | 873 | config SND_VX222 |
| 925 | tristate "Digigram VX222" | 874 | tristate "Digigram VX222" |
| 926 | depends on SND | ||
| 927 | select SND_VX_LIB | 875 | select SND_VX_LIB |
| 928 | help | 876 | help |
| 929 | Say Y here to include support for Digigram VX222 soundcards. | 877 | Say Y here to include support for Digigram VX222 soundcards. |
| @@ -933,7 +881,6 @@ config SND_VX222 | |||
| 933 | 881 | ||
| 934 | config SND_YMFPCI | 882 | config SND_YMFPCI |
| 935 | tristate "Yamaha YMF724/740/744/754" | 883 | tristate "Yamaha YMF724/740/744/754" |
| 936 | depends on SND | ||
| 937 | select FW_LOADER if !SND_YMFPCI_FIRMWARE_IN_KERNEL | 884 | select FW_LOADER if !SND_YMFPCI_FIRMWARE_IN_KERNEL |
| 938 | select SND_OPL3_LIB | 885 | select SND_OPL3_LIB |
| 939 | select SND_MPU401_UART | 886 | select SND_MPU401_UART |
| @@ -954,25 +901,4 @@ config SND_YMFPCI_FIRMWARE_IN_KERNEL | |||
| 954 | for the YMFPCI driver. If you choose N here, you need to | 901 | for the YMFPCI driver. If you choose N here, you need to |
| 955 | install the firmware files from the alsa-firmware package. | 902 | install the firmware files from the alsa-firmware package. |
| 956 | 903 | ||
| 957 | config SND_AC97_POWER_SAVE | 904 | endif # SND_PCI |
| 958 | bool "AC97 Power-Saving Mode" | ||
| 959 | depends on SND_AC97_CODEC && EXPERIMENTAL | ||
| 960 | default n | ||
| 961 | help | ||
| 962 | Say Y here to enable the aggressive power-saving support of | ||
| 963 | AC97 codecs. In this mode, the power-mode is dynamically | ||
| 964 | controlled at each open/close. | ||
| 965 | |||
| 966 | The mode is activated by passing power_save=1 option to | ||
| 967 | snd-ac97-codec driver. You can toggle it dynamically over | ||
| 968 | sysfs, too. | ||
| 969 | |||
| 970 | config SND_AC97_POWER_SAVE_DEFAULT | ||
| 971 | int "Default time-out for AC97 power-save mode" | ||
| 972 | depends on SND_AC97_POWER_SAVE | ||
| 973 | default 0 | ||
| 974 | help | ||
| 975 | The default time-out value in seconds for AC97 automatic | ||
| 976 | power-save mode. 0 means to disable the power-save mode. | ||
| 977 | |||
| 978 | endmenu | ||
diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 85ef14bc8056..65b25d221cd2 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile | |||
| @@ -13,7 +13,7 @@ snd-bt87x-objs := bt87x.o | |||
| 13 | snd-cmipci-objs := cmipci.o | 13 | snd-cmipci-objs := cmipci.o |
| 14 | snd-cs4281-objs := cs4281.o | 14 | snd-cs4281-objs := cs4281.o |
| 15 | snd-cs5530-objs := cs5530.o | 15 | snd-cs5530-objs := cs5530.o |
| 16 | snd-ens1370-objs := ens1370.o | 16 | snd-ens1370-objs := ens1370.o ak4531_codec.o |
| 17 | snd-ens1371-objs := ens1371.o | 17 | snd-ens1371-objs := ens1371.o |
| 18 | snd-es1938-objs := es1938.o | 18 | snd-es1938-objs := es1938.o |
| 19 | snd-es1968-objs := es1968.o | 19 | snd-es1968-objs := es1968.o |
diff --git a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile index 0be48b1a22d0..41fa322f0971 100644 --- a/sound/pci/ac97/Makefile +++ b/sound/pci/ac97/Makefile | |||
| @@ -3,16 +3,8 @@ | |||
| 3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> | 3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> |
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o | 6 | snd-ac97-codec-y := ac97_codec.o ac97_pcm.o |
| 7 | 7 | snd-ac97-codec-$(CONFIG_PROC_FS) += ac97_proc.o | |
| 8 | ifneq ($(CONFIG_PROC_FS),) | ||
| 9 | snd-ac97-codec-objs += ac97_proc.o | ||
| 10 | endif | ||
| 11 | |||
| 12 | snd-ak4531-codec-objs := ak4531_codec.o | ||
| 13 | 8 | ||
| 14 | # Toplevel Module Dependency | 9 | # Toplevel Module Dependency |
| 15 | obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o | 10 | obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o |
| 16 | obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o | ||
| 17 | |||
| 18 | obj-m := $(sort $(obj-m)) | ||
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 45fd29017ddd..07364c00768a 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
| @@ -49,8 +49,9 @@ MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); | |||
| 49 | 49 | ||
| 50 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 50 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
| 51 | static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT; | 51 | static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT; |
| 52 | module_param(power_save, bool, 0644); | 52 | module_param(power_save, int, 0644); |
| 53 | MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); | 53 | MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " |
| 54 | "(in second, 0 = disable)."); | ||
| 54 | #endif | 55 | #endif |
| 55 | /* | 56 | /* |
| 56 | 57 | ||
| @@ -2294,9 +2295,11 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) | |||
| 2294 | power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ | 2295 | power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ |
| 2295 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2296 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
| 2296 | udelay(100); | 2297 | udelay(100); |
| 2297 | power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ | 2298 | power |= AC97_PD_PR2; /* Analog Mixer powerdown (Vref on) */ |
| 2298 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2299 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
| 2299 | if (ac97_is_power_save_mode(ac97)) { | 2300 | if (ac97_is_power_save_mode(ac97)) { |
| 2301 | power |= AC97_PD_PR3; /* Analog Mixer powerdown */ | ||
| 2302 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | ||
| 2300 | udelay(100); | 2303 | udelay(100); |
| 2301 | /* AC-link powerdown, internal Clk disable */ | 2304 | /* AC-link powerdown, internal Clk disable */ |
| 2302 | /* FIXME: this may cause click noises on some boards */ | 2305 | /* FIXME: this may cause click noises on some boards */ |
| @@ -2362,7 +2365,7 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) | |||
| 2362 | * that open/close frequently) | 2365 | * that open/close frequently) |
| 2363 | */ | 2366 | */ |
| 2364 | schedule_delayed_work(&ac97->power_work, | 2367 | schedule_delayed_work(&ac97->power_work, |
| 2365 | msecs_to_jiffies(2000)); | 2368 | msecs_to_jiffies(power_save * 1000)); |
| 2366 | else { | 2369 | else { |
| 2367 | cancel_delayed_work(&ac97->power_work); | 2370 | cancel_delayed_work(&ac97->power_work); |
| 2368 | update_power_regs(ac97); | 2371 | update_power_regs(ac97); |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1292dcee072d..0746e9ccc20b 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
| @@ -669,6 +669,7 @@ AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), | |||
| 669 | AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), | 669 | AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), |
| 670 | AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), | 670 | AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), |
| 671 | 671 | ||
| 672 | AC97_SINGLE("Master Left Inv Switch", AC97_MASTER, 6, 1, 0), | ||
| 672 | AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0), | 673 | AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0), |
| 673 | AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0), | 674 | AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0), |
| 674 | AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0), | 675 | AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0), |
| @@ -3352,8 +3353,66 @@ AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), | |||
| 3352 | AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), | 3353 | AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), |
| 3353 | }; | 3354 | }; |
| 3354 | 3355 | ||
| 3356 | static const char *slave_vols_vt1616[] = { | ||
| 3357 | "Front Playback Volume", | ||
| 3358 | "Surround Playback Volume", | ||
| 3359 | "Center Playback Volume", | ||
| 3360 | "LFE Playback Volume", | ||
| 3361 | NULL | ||
| 3362 | }; | ||
| 3363 | |||
| 3364 | static const char *slave_sws_vt1616[] = { | ||
| 3365 | "Front Playback Switch", | ||
| 3366 | "Surround Playback Switch", | ||
| 3367 | "Center Playback Switch", | ||
| 3368 | "LFE Playback Switch", | ||
| 3369 | NULL | ||
| 3370 | }; | ||
| 3371 | |||
| 3372 | /* find a mixer control element with the given name */ | ||
| 3373 | static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, | ||
| 3374 | const char *name) | ||
| 3375 | { | ||
| 3376 | struct snd_ctl_elem_id id; | ||
| 3377 | memset(&id, 0, sizeof(id)); | ||
| 3378 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
| 3379 | strcpy(id.name, name); | ||
| 3380 | return snd_ctl_find_id(ac97->bus->card, &id); | ||
| 3381 | } | ||
| 3382 | |||
| 3383 | /* create a virtual master control and add slaves */ | ||
| 3384 | int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, | ||
| 3385 | const unsigned int *tlv, const char **slaves) | ||
| 3386 | { | ||
| 3387 | struct snd_kcontrol *kctl; | ||
| 3388 | const char **s; | ||
| 3389 | int err; | ||
| 3390 | |||
| 3391 | kctl = snd_ctl_make_virtual_master(name, tlv); | ||
| 3392 | if (!kctl) | ||
| 3393 | return -ENOMEM; | ||
| 3394 | err = snd_ctl_add(ac97->bus->card, kctl); | ||
| 3395 | if (err < 0) | ||
| 3396 | return err; | ||
| 3397 | |||
| 3398 | for (s = slaves; *s; s++) { | ||
| 3399 | struct snd_kcontrol *sctl; | ||
| 3400 | |||
| 3401 | sctl = snd_ac97_find_mixer_ctl(ac97, *s); | ||
| 3402 | if (!sctl) { | ||
| 3403 | snd_printdd("Cannot find slave %s, skipped\n", *s); | ||
| 3404 | continue; | ||
| 3405 | } | ||
| 3406 | err = snd_ctl_add_slave(kctl, sctl); | ||
| 3407 | if (err < 0) | ||
| 3408 | return err; | ||
| 3409 | } | ||
| 3410 | return 0; | ||
| 3411 | } | ||
| 3412 | |||
| 3355 | static int patch_vt1616_specific(struct snd_ac97 * ac97) | 3413 | static int patch_vt1616_specific(struct snd_ac97 * ac97) |
| 3356 | { | 3414 | { |
| 3415 | struct snd_kcontrol *kctl; | ||
| 3357 | int err; | 3416 | int err; |
| 3358 | 3417 | ||
| 3359 | if (snd_ac97_try_bit(ac97, 0x5a, 9)) | 3418 | if (snd_ac97_try_bit(ac97, 0x5a, 9)) |
| @@ -3361,6 +3420,24 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97) | |||
| 3361 | return err; | 3420 | return err; |
| 3362 | if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) | 3421 | if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) |
| 3363 | return err; | 3422 | return err; |
| 3423 | |||
| 3424 | /* There is already a misnamed master switch. Rename it. */ | ||
| 3425 | kctl = snd_ac97_find_mixer_ctl(ac97, "Master Playback Volume"); | ||
| 3426 | if (!kctl) | ||
| 3427 | return -EINVAL; | ||
| 3428 | |||
| 3429 | snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Front Playback"); | ||
| 3430 | |||
| 3431 | err = snd_ac97_add_vmaster(ac97, "Master Playback Volume", | ||
| 3432 | kctl->tlv.p, slave_vols_vt1616); | ||
| 3433 | if (err < 0) | ||
| 3434 | return err; | ||
| 3435 | |||
| 3436 | err = snd_ac97_add_vmaster(ac97, "Master Playback Switch", | ||
| 3437 | NULL, slave_sws_vt1616); | ||
| 3438 | if (err < 0) | ||
| 3439 | return err; | ||
| 3440 | |||
| 3364 | return 0; | 3441 | return 0; |
| 3365 | } | 3442 | } |
| 3366 | 3443 | ||
| @@ -3633,7 +3710,7 @@ static int patch_ucb1400(struct snd_ac97 * ac97) | |||
| 3633 | { | 3710 | { |
| 3634 | ac97->build_ops = &patch_ucb1400_ops; | 3711 | ac97->build_ops = &patch_ucb1400_ops; |
| 3635 | /* enable headphone driver and smart low power mode by default */ | 3712 | /* enable headphone driver and smart low power mode by default */ |
| 3636 | snd_ac97_write(ac97, 0x6a, 0x0050); | 3713 | snd_ac97_write_cache(ac97, 0x6a, 0x0050); |
| 3637 | snd_ac97_write(ac97, 0x6c, 0x0030); | 3714 | snd_ac97_write_cache(ac97, 0x6c, 0x0030); |
| 3638 | return 0; | 3715 | return 0; |
| 3639 | } | 3716 | } |
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ak4531_codec.c index c0c1633999ea..33d37b1c42fc 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c | |||
| @@ -28,9 +28,11 @@ | |||
| 28 | #include <sound/ak4531_codec.h> | 28 | #include <sound/ak4531_codec.h> |
| 29 | #include <sound/tlv.h> | 29 | #include <sound/tlv.h> |
| 30 | 30 | ||
| 31 | /* | ||
| 31 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 32 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
| 32 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); | 33 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); |
| 33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
| 35 | */ | ||
| 34 | 36 | ||
| 35 | #ifdef CONFIG_PROC_FS | 37 | #ifdef CONFIG_PROC_FS |
| 36 | static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531); | 38 | static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531); |
| @@ -270,7 +272,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); | |||
| 270 | static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); | 272 | static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); |
| 271 | static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); | 273 | static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); |
| 272 | 274 | ||
| 273 | static struct snd_kcontrol_new snd_ak4531_controls[] = { | 275 | static struct snd_kcontrol_new snd_ak4531_controls[] __devinitdata = { |
| 274 | 276 | ||
| 275 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, | 277 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, |
| 276 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, | 278 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, |
| @@ -379,8 +381,9 @@ static u8 snd_ak4531_initial_map[0x19 + 1] = { | |||
| 379 | 0x01 /* 19: Mic Amp Setup */ | 381 | 0x01 /* 19: Mic Amp Setup */ |
| 380 | }; | 382 | }; |
| 381 | 383 | ||
| 382 | int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531, | 384 | int __devinit snd_ak4531_mixer(struct snd_card *card, |
| 383 | struct snd_ak4531 **rak4531) | 385 | struct snd_ak4531 *_ak4531, |
| 386 | struct snd_ak4531 **rak4531) | ||
| 384 | { | 387 | { |
| 385 | unsigned int idx; | 388 | unsigned int idx; |
| 386 | int err; | 389 | int err; |
| @@ -476,7 +479,8 @@ static void snd_ak4531_proc_read(struct snd_info_entry *entry, | |||
| 476 | ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); | 479 | ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); |
| 477 | } | 480 | } |
| 478 | 481 | ||
| 479 | static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) | 482 | static void __devinit |
| 483 | snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) | ||
| 480 | { | 484 | { |
| 481 | struct snd_info_entry *entry; | 485 | struct snd_info_entry *entry; |
| 482 | 486 | ||
| @@ -484,25 +488,3 @@ static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak453 | |||
| 484 | snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); | 488 | snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); |
| 485 | } | 489 | } |
| 486 | #endif | 490 | #endif |
| 487 | |||
| 488 | EXPORT_SYMBOL(snd_ak4531_mixer); | ||
| 489 | #ifdef CONFIG_PM | ||
| 490 | EXPORT_SYMBOL(snd_ak4531_suspend); | ||
| 491 | EXPORT_SYMBOL(snd_ak4531_resume); | ||
| 492 | #endif | ||
| 493 | |||
| 494 | /* | ||
| 495 | * INIT part | ||
| 496 | */ | ||
| 497 | |||
| 498 | static int __init alsa_ak4531_init(void) | ||
| 499 | { | ||
| 500 | return 0; | ||
| 501 | } | ||
| 502 | |||
| 503 | static void __exit alsa_ak4531_exit(void) | ||
| 504 | { | ||
| 505 | } | ||
| 506 | |||
| 507 | module_init(alsa_ak4531_init) | ||
| 508 | module_exit(alsa_ak4531_exit) | ||
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index bc212f41a38a..e291aa59742e 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $Id: au88x0_game.c,v 1.9 2003/09/22 03:51:28 mjander Exp $ | ||
| 3 | * | ||
| 4 | * Manuel Jander. | 2 | * Manuel Jander. |
| 5 | * | 3 | * |
| 6 | * Based on the work of: | 4 | * Based on the work of: |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 5f63af6b88a2..22f18f3cfbc9 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). | 2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). |
| 3 | * Copyright (C) 2002, 2005, 2006, 2007 by Andreas Mohr <andi AT lisas.de> | 3 | * Copyright (C) 2002, 2005 - 2008 by Andreas Mohr <andi AT lisas.de> |
| 4 | * | 4 | * |
| 5 | * Framework borrowed from Bart Hartgers's als4000.c. | 5 | * Framework borrowed from Bart Hartgers's als4000.c. |
| 6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), | 6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), |
| @@ -35,9 +35,20 @@ | |||
| 35 | * (3 weeks' worth of evenings filled with driver work). | 35 | * (3 weeks' worth of evenings filled with driver work). |
| 36 | * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros) | 36 | * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros) |
| 37 | * | 37 | * |
| 38 | * It is quite likely that the AZF3328 chip is the PCI cousin of the | ||
| 39 | * AZF3318 ("azt1020 pnp", "MM Pro 16") ISA chip, given very similar specs. | ||
| 40 | * | ||
| 38 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name | 41 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name |
| 39 | * for compatibility reasons) has the following features: | 42 | * for compatibility reasons) from Azfin (joint-venture of Aztech and Fincitec, |
| 43 | * Fincitec acquired by National Semiconductor in 2002, together with the | ||
| 44 | * Fincitec-related company ARSmikro) has the following features: | ||
| 40 | * | 45 | * |
| 46 | * - compatibility & compliance: | ||
| 47 | * - Microsoft PC 97 ("PC 97 Hardware Design Guide", | ||
| 48 | * http://www.microsoft.com/whdc/archive/pcguides.mspx) | ||
| 49 | * - Microsoft PC 98 Baseline Audio | ||
| 50 | * - MPU401 UART | ||
| 51 | * - Sound Blaster Emulation (DOS Box) | ||
| 41 | * - builtin AC97 conformant codec (SNR over 80dB) | 52 | * - builtin AC97 conformant codec (SNR over 80dB) |
| 42 | * Note that "conformant" != "compliant"!! this chip's mixer register layout | 53 | * Note that "conformant" != "compliant"!! this chip's mixer register layout |
| 43 | * *differs* from the standard AC97 layout: | 54 | * *differs* from the standard AC97 layout: |
| @@ -48,21 +59,28 @@ | |||
| 48 | * addresses illegally. So far unfortunately it looks like the very flexible | 59 | * addresses illegally. So far unfortunately it looks like the very flexible |
| 49 | * ALSA AC97 support is still not enough to easily compensate for such a | 60 | * ALSA AC97 support is still not enough to easily compensate for such a |
| 50 | * grave layout violation despite all tweaks and quirks mechanisms it offers. | 61 | * grave layout violation despite all tweaks and quirks mechanisms it offers. |
| 51 | * - builtin genuine OPL3 | 62 | * - builtin genuine OPL3 - verified to work fine, 20080506 |
| 52 | * - full duplex 16bit playback/record at independent sampling rate | 63 | * - full duplex 16bit playback/record at independent sampling rate |
| 53 | * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? | 64 | * - MPU401 (+ legacy address support, claimed by one official spec sheet) |
| 65 | * FIXME: how to enable legacy addr?? | ||
| 54 | * - game port (legacy address support) | 66 | * - game port (legacy address support) |
| 55 | * - builtin 3D enhancement (said to be YAMAHA Ymersion) | ||
| 56 | * - builtin DirectInput support, helps reduce CPU overhead (interrupt-driven | 67 | * - builtin DirectInput support, helps reduce CPU overhead (interrupt-driven |
| 57 | * features supported) | 68 | * features supported). - See common term "Digital Enhanced Game Port"... |
| 69 | * (probably DirectInput 3.0 spec - confirm) | ||
| 70 | * - builtin 3D enhancement (said to be YAMAHA Ymersion) | ||
| 58 | * - built-in General DirectX timer having a 20 bits counter | 71 | * - built-in General DirectX timer having a 20 bits counter |
| 59 | * with 1us resolution (see below!) | 72 | * with 1us resolution (see below!) |
| 60 | * - I2S serial port for external DAC | 73 | * - I2S serial output port for external DAC |
| 61 | * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI | 74 | * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI |
| 62 | * - supports hardware volume control | 75 | * - supports hardware volume control |
| 63 | * - single chip low cost solution (128 pin QFP) | 76 | * - single chip low cost solution (128 pin QFP) |
| 64 | * - supports programmable Sub-vendor and Sub-system ID | 77 | * - supports programmable Sub-vendor and Sub-system ID |
| 65 | * required for Microsoft's logo compliance (FIXME: where?) | 78 | * required for Microsoft's logo compliance (FIXME: where?) |
| 79 | * At least the Trident 4D Wave DX has one bit somewhere | ||
| 80 | * to enable writes to PCI subsystem VID registers, that should be it. | ||
| 81 | * This might easily be in extended PCI reg space, since PCI168 also has | ||
| 82 | * some custom data starting at 0x80. What kind of config settings | ||
| 83 | * are located in our extended PCI space anyway?? | ||
| 66 | * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms | 84 | * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms |
| 67 | * | 85 | * |
| 68 | * Note that this driver now is actually *better* than the Windows driver, | 86 | * Note that this driver now is actually *better* than the Windows driver, |
| @@ -74,6 +92,24 @@ | |||
| 74 | * - "timidity -iAv -B2,8 -Os -EFreverb=0" | 92 | * - "timidity -iAv -B2,8 -Os -EFreverb=0" |
| 75 | * - "pmidi -p 128:0 jazz.mid" | 93 | * - "pmidi -p 128:0 jazz.mid" |
| 76 | * | 94 | * |
| 95 | * OPL3 hardware playback testing, try something like: | ||
| 96 | * cat /proc/asound/hwdep | ||
| 97 | * and | ||
| 98 | * aconnect -o | ||
| 99 | * Then use | ||
| 100 | * sbiload -Dhw:x,y --opl3 /usr/share/sounds/opl3/std.o3 ......./drums.o3 | ||
| 101 | * where x,y is the xx-yy number as given in hwdep. | ||
| 102 | * Then try | ||
| 103 | * pmidi -p a:b jazz.mid | ||
| 104 | * where a:b is the client number plus 0 usually, as given by aconnect above. | ||
| 105 | * Oh, and make sure to unmute the FM mixer control (doh!) | ||
| 106 | * NOTE: power use during OPL3 playback is _VERY_ high (70W --> 90W!) | ||
| 107 | * despite no CPU activity, possibly due to hindering ACPI idling somehow. | ||
| 108 | * Shouldn't be a problem of the AZF3328 chip itself, I'd hope. | ||
| 109 | * Higher PCM / FM mixer levels seem to conflict (causes crackling), | ||
| 110 | * at least sometimes. Maybe even use with hardware sequencer timer above :) | ||
| 111 | * adplay/adplug-utils might soon offer hardware-based OPL3 playback, too. | ||
| 112 | * | ||
| 77 | * Certain PCI versions of this card are susceptible to DMA traffic underruns | 113 | * Certain PCI versions of this card are susceptible to DMA traffic underruns |
| 78 | * in some systems (resulting in sound crackling/clicking/popping), | 114 | * in some systems (resulting in sound crackling/clicking/popping), |
| 79 | * probably because they don't have a DMA FIFO buffer or so. | 115 | * probably because they don't have a DMA FIFO buffer or so. |
| @@ -87,6 +123,8 @@ | |||
| 87 | * better than a VIA, yet ironically I still get crackling, like many other | 123 | * better than a VIA, yet ironically I still get crackling, like many other |
| 88 | * people with the same chipset. | 124 | * people with the same chipset. |
| 89 | * Possible remedies: | 125 | * Possible remedies: |
| 126 | * - use speaker (amplifier) output instead of headphone output | ||
| 127 | * (in case crackling is due to overloaded output clipping) | ||
| 90 | * - plug card into a different PCI slot, preferrably one that isn't shared | 128 | * - plug card into a different PCI slot, preferrably one that isn't shared |
| 91 | * too much (this helps a lot, but not completely!) | 129 | * too much (this helps a lot, but not completely!) |
| 92 | * - get rid of PCI VGA card, use AGP instead | 130 | * - get rid of PCI VGA card, use AGP instead |
| @@ -94,18 +132,23 @@ | |||
| 94 | * - fiddle with PCI latency settings (setpci -v -s BUSID latency_timer=XX) | 132 | * - fiddle with PCI latency settings (setpci -v -s BUSID latency_timer=XX) |
| 95 | * Not too helpful. | 133 | * Not too helpful. |
| 96 | * - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS | 134 | * - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS |
| 97 | * | 135 | * |
| 98 | * BUGS | 136 | * BUGS |
| 99 | * - full-duplex might *still* be problematic, not fully tested recently | 137 | * - full-duplex might *still* be problematic, however a recent test was fine |
| 100 | * - (non-bug) "Bass/Treble or 3D settings don't work" - they do get evaluated | 138 | * - (non-bug) "Bass/Treble or 3D settings don't work" - they do get evaluated |
| 101 | * if you set PCM output switch to "pre 3D" instead of "post 3D". | 139 | * if you set PCM output switch to "pre 3D" instead of "post 3D". |
| 102 | * If this can't be set, then get a mixer application that Isn't Stupid (tm) | 140 | * If this can't be set, then get a mixer application that Isn't Stupid (tm) |
| 103 | * (e.g. kmix, gamix) - unfortunately several are!! | 141 | * (e.g. kmix, gamix) - unfortunately several are!! |
| 104 | * | 142 | * - locking is not entirely clean, especially the audio stream activity |
| 143 | * ints --> may be racy | ||
| 144 | * - an _unconnected_ secondary joystick at the gameport will be reported | ||
| 145 | * to be "active" (floating values, not precisely -1) due to the way we need | ||
| 146 | * to read the Digital Enhanced Game Port. Not sure whether it is fixable. | ||
| 147 | * | ||
| 105 | * TODO | 148 | * TODO |
| 106 | * - test MPU401 MIDI playback etc. | 149 | * - test MPU401 MIDI playback etc. |
| 107 | * - add some power micro-management (disable various units of the card | 150 | * - add more power micro-management (disable various units of the card |
| 108 | * as long as they're unused). However this requires I/O ports which I | 151 | * as long as they're unused). However this requires more I/O ports which I |
| 109 | * haven't figured out yet and which thus might not even exist... | 152 | * haven't figured out yet and which thus might not even exist... |
| 110 | * The standard suspend/resume functionality could probably make use of | 153 | * The standard suspend/resume functionality could probably make use of |
| 111 | * some improvement, too... | 154 | * some improvement, too... |
| @@ -113,6 +156,7 @@ | |||
| 113 | * - figure out some cleverly evil scheme to possibly make ALSA AC97 code | 156 | * - figure out some cleverly evil scheme to possibly make ALSA AC97 code |
| 114 | * fully accept our quite incompatible ""AC97"" mixer and thus save some | 157 | * fully accept our quite incompatible ""AC97"" mixer and thus save some |
| 115 | * code (but I'm not too optimistic that doing this is possible at all) | 158 | * code (but I'm not too optimistic that doing this is possible at all) |
| 159 | * - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport. | ||
| 116 | */ | 160 | */ |
| 117 | 161 | ||
| 118 | #include <asm/io.h> | 162 | #include <asm/io.h> |
| @@ -138,7 +182,7 @@ MODULE_LICENSE("GPL"); | |||
| 138 | MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | 182 | MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); |
| 139 | 183 | ||
| 140 | #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) | 184 | #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) |
| 141 | #define SUPPORT_JOYSTICK 1 | 185 | #define SUPPORT_GAMEPORT 1 |
| 142 | #endif | 186 | #endif |
| 143 | 187 | ||
| 144 | #define DEBUG_MISC 0 | 188 | #define DEBUG_MISC 0 |
| @@ -147,13 +191,14 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
| 147 | #define DEBUG_PLAY_REC 0 | 191 | #define DEBUG_PLAY_REC 0 |
| 148 | #define DEBUG_IO 0 | 192 | #define DEBUG_IO 0 |
| 149 | #define DEBUG_TIMER 0 | 193 | #define DEBUG_TIMER 0 |
| 194 | #define DEBUG_GAME 0 | ||
| 150 | #define MIXER_TESTING 0 | 195 | #define MIXER_TESTING 0 |
| 151 | 196 | ||
| 152 | #if DEBUG_MISC | 197 | #if DEBUG_MISC |
| 153 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) | 198 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) |
| 154 | #else | 199 | #else |
| 155 | #define snd_azf3328_dbgmisc(format, args...) | 200 | #define snd_azf3328_dbgmisc(format, args...) |
| 156 | #endif | 201 | #endif |
| 157 | 202 | ||
| 158 | #if DEBUG_CALLS | 203 | #if DEBUG_CALLS |
| 159 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) | 204 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) |
| @@ -163,25 +208,31 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
| 163 | #define snd_azf3328_dbgcalls(format, args...) | 208 | #define snd_azf3328_dbgcalls(format, args...) |
| 164 | #define snd_azf3328_dbgcallenter() | 209 | #define snd_azf3328_dbgcallenter() |
| 165 | #define snd_azf3328_dbgcallleave() | 210 | #define snd_azf3328_dbgcallleave() |
| 166 | #endif | 211 | #endif |
| 167 | 212 | ||
| 168 | #if DEBUG_MIXER | 213 | #if DEBUG_MIXER |
| 169 | #define snd_azf3328_dbgmixer(format, args...) printk(format, ##args) | 214 | #define snd_azf3328_dbgmixer(format, args...) printk(format, ##args) |
| 170 | #else | 215 | #else |
| 171 | #define snd_azf3328_dbgmixer(format, args...) | 216 | #define snd_azf3328_dbgmixer(format, args...) |
| 172 | #endif | 217 | #endif |
| 173 | 218 | ||
| 174 | #if DEBUG_PLAY_REC | 219 | #if DEBUG_PLAY_REC |
| 175 | #define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args) | 220 | #define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args) |
| 176 | #else | 221 | #else |
| 177 | #define snd_azf3328_dbgplay(format, args...) | 222 | #define snd_azf3328_dbgplay(format, args...) |
| 178 | #endif | 223 | #endif |
| 179 | 224 | ||
| 180 | #if DEBUG_MISC | 225 | #if DEBUG_MISC |
| 181 | #define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args) | 226 | #define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args) |
| 182 | #else | 227 | #else |
| 183 | #define snd_azf3328_dbgtimer(format, args...) | 228 | #define snd_azf3328_dbgtimer(format, args...) |
| 184 | #endif | 229 | #endif |
| 230 | |||
| 231 | #if DEBUG_GAME | ||
| 232 | #define snd_azf3328_dbggame(format, args...) printk(KERN_ERR format, ##args) | ||
| 233 | #else | ||
| 234 | #define snd_azf3328_dbggame(format, args...) | ||
| 235 | #endif | ||
| 185 | 236 | ||
| 186 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 237 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 187 | module_param_array(index, int, NULL, 0444); | 238 | module_param_array(index, int, NULL, 0444); |
| @@ -195,51 +246,62 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * | |||
| 195 | module_param_array(enable, bool, NULL, 0444); | 246 | module_param_array(enable, bool, NULL, 0444); |
| 196 | MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); | 247 | MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); |
| 197 | 248 | ||
| 198 | #ifdef SUPPORT_JOYSTICK | ||
| 199 | static int joystick[SNDRV_CARDS]; | ||
| 200 | module_param_array(joystick, bool, NULL, 0444); | ||
| 201 | MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard."); | ||
| 202 | #endif | ||
| 203 | |||
| 204 | static int seqtimer_scaling = 128; | 249 | static int seqtimer_scaling = 128; |
| 205 | module_param(seqtimer_scaling, int, 0444); | 250 | module_param(seqtimer_scaling, int, 0444); |
| 206 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); | 251 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); |
| 207 | 252 | ||
| 253 | struct snd_azf3328_audio_stream { | ||
| 254 | struct snd_pcm_substream *substream; | ||
| 255 | int enabled; | ||
| 256 | int running; | ||
| 257 | unsigned long portbase; | ||
| 258 | }; | ||
| 259 | |||
| 260 | enum snd_azf3328_stream_index { | ||
| 261 | AZF_PLAYBACK = 0, | ||
| 262 | AZF_CAPTURE = 1, | ||
| 263 | }; | ||
| 264 | |||
| 208 | struct snd_azf3328 { | 265 | struct snd_azf3328 { |
| 209 | /* often-used fields towards beginning, then grouped */ | 266 | /* often-used fields towards beginning, then grouped */ |
| 210 | unsigned long codec_port; | 267 | |
| 211 | unsigned long io2_port; | 268 | unsigned long codec_io; /* usually 0xb000, size 128 */ |
| 212 | unsigned long mpu_port; | 269 | unsigned long game_io; /* usually 0xb400, size 8 */ |
| 213 | unsigned long synth_port; | 270 | unsigned long mpu_io; /* usually 0xb800, size 4 */ |
| 214 | unsigned long mixer_port; | 271 | unsigned long opl3_io; /* usually 0xbc00, size 8 */ |
| 272 | unsigned long mixer_io; /* usually 0xc000, size 64 */ | ||
| 215 | 273 | ||
| 216 | spinlock_t reg_lock; | 274 | spinlock_t reg_lock; |
| 217 | 275 | ||
| 218 | struct snd_timer *timer; | 276 | struct snd_timer *timer; |
| 219 | 277 | ||
| 220 | struct snd_pcm *pcm; | 278 | struct snd_pcm *pcm; |
| 221 | struct snd_pcm_substream *playback_substream; | 279 | struct snd_azf3328_audio_stream audio_stream[2]; |
| 222 | struct snd_pcm_substream *capture_substream; | ||
| 223 | unsigned int is_playing; | ||
| 224 | unsigned int is_recording; | ||
| 225 | 280 | ||
| 226 | struct snd_card *card; | 281 | struct snd_card *card; |
| 227 | struct snd_rawmidi *rmidi; | 282 | struct snd_rawmidi *rmidi; |
| 228 | 283 | ||
| 229 | #ifdef SUPPORT_JOYSTICK | 284 | #ifdef SUPPORT_GAMEPORT |
| 230 | struct gameport *gameport; | 285 | struct gameport *gameport; |
| 286 | int axes[4]; | ||
| 231 | #endif | 287 | #endif |
| 232 | 288 | ||
| 233 | struct pci_dev *pci; | 289 | struct pci_dev *pci; |
| 234 | int irq; | 290 | int irq; |
| 235 | 291 | ||
| 292 | /* register 0x6a is write-only, thus need to remember setting. | ||
| 293 | * If we need to add more registers here, then we might try to fold this | ||
| 294 | * into some transparent combined shadow register handling with | ||
| 295 | * CONFIG_PM register storage below, but that's slightly difficult. */ | ||
| 296 | u16 shadow_reg_codec_6AH; | ||
| 297 | |||
| 236 | #ifdef CONFIG_PM | 298 | #ifdef CONFIG_PM |
| 237 | /* register value containers for power management | 299 | /* register value containers for power management |
| 238 | * Note: not always full I/O range preserved (just like Win driver!) */ | 300 | * Note: not always full I/O range preserved (just like Win driver!) */ |
| 239 | u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2]; | 301 | u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2]; |
| 240 | u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2]; | 302 | u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; |
| 241 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | 303 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; |
| 242 | u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2]; | 304 | u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; |
| 243 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; | 305 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; |
| 244 | #endif | 306 | #endif |
| 245 | }; | 307 | }; |
| @@ -252,126 +314,166 @@ static const struct pci_device_id snd_azf3328_ids[] = { | |||
| 252 | 314 | ||
| 253 | MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); | 315 | MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); |
| 254 | 316 | ||
| 317 | |||
| 318 | static int | ||
| 319 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) | ||
| 320 | { | ||
| 321 | u8 prev = inb(reg), new; | ||
| 322 | |||
| 323 | new = (do_set) ? (prev|mask) : (prev & ~mask); | ||
| 324 | /* we need to always write the new value no matter whether it differs | ||
| 325 | * or not, since some register bits don't indicate their setting */ | ||
| 326 | outb(new, reg); | ||
| 327 | if (new != prev) | ||
| 328 | return 1; | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 255 | static inline void | 333 | static inline void |
| 256 | snd_azf3328_codec_outb(const struct snd_azf3328 *chip, int reg, u8 value) | 334 | snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) |
| 257 | { | 335 | { |
| 258 | outb(value, chip->codec_port + reg); | 336 | outb(value, chip->codec_io + reg); |
| 259 | } | 337 | } |
| 260 | 338 | ||
| 261 | static inline u8 | 339 | static inline u8 |
| 262 | snd_azf3328_codec_inb(const struct snd_azf3328 *chip, int reg) | 340 | snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg) |
| 263 | { | 341 | { |
| 264 | return inb(chip->codec_port + reg); | 342 | return inb(chip->codec_io + reg); |
| 265 | } | 343 | } |
| 266 | 344 | ||
| 267 | static inline void | 345 | static inline void |
| 268 | snd_azf3328_codec_outw(const struct snd_azf3328 *chip, int reg, u16 value) | 346 | snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) |
| 269 | { | 347 | { |
| 270 | outw(value, chip->codec_port + reg); | 348 | outw(value, chip->codec_io + reg); |
| 271 | } | 349 | } |
| 272 | 350 | ||
| 273 | static inline u16 | 351 | static inline u16 |
| 274 | snd_azf3328_codec_inw(const struct snd_azf3328 *chip, int reg) | 352 | snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg) |
| 353 | { | ||
| 354 | return inw(chip->codec_io + reg); | ||
| 355 | } | ||
| 356 | |||
| 357 | static inline void | ||
| 358 | snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) | ||
| 359 | { | ||
| 360 | outl(value, chip->codec_io + reg); | ||
| 361 | } | ||
| 362 | |||
| 363 | static inline u32 | ||
| 364 | snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg) | ||
| 275 | { | 365 | { |
| 276 | return inw(chip->codec_port + reg); | 366 | return inl(chip->codec_io + reg); |
| 277 | } | 367 | } |
| 278 | 368 | ||
| 279 | static inline void | 369 | static inline void |
| 280 | snd_azf3328_codec_outl(const struct snd_azf3328 *chip, int reg, u32 value) | 370 | snd_azf3328_game_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) |
| 281 | { | 371 | { |
| 282 | outl(value, chip->codec_port + reg); | 372 | outb(value, chip->game_io + reg); |
| 283 | } | 373 | } |
| 284 | 374 | ||
| 285 | static inline void | 375 | static inline void |
| 286 | snd_azf3328_io2_outb(const struct snd_azf3328 *chip, int reg, u8 value) | 376 | snd_azf3328_game_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) |
| 287 | { | 377 | { |
| 288 | outb(value, chip->io2_port + reg); | 378 | outw(value, chip->game_io + reg); |
| 289 | } | 379 | } |
| 290 | 380 | ||
| 291 | static inline u8 | 381 | static inline u8 |
| 292 | snd_azf3328_io2_inb(const struct snd_azf3328 *chip, int reg) | 382 | snd_azf3328_game_inb(const struct snd_azf3328 *chip, unsigned reg) |
| 293 | { | 383 | { |
| 294 | return inb(chip->io2_port + reg); | 384 | return inb(chip->game_io + reg); |
| 385 | } | ||
| 386 | |||
| 387 | static inline u16 | ||
| 388 | snd_azf3328_game_inw(const struct snd_azf3328 *chip, unsigned reg) | ||
| 389 | { | ||
| 390 | return inw(chip->game_io + reg); | ||
| 295 | } | 391 | } |
| 296 | 392 | ||
| 297 | static inline void | 393 | static inline void |
| 298 | snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, int reg, u16 value) | 394 | snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) |
| 299 | { | 395 | { |
| 300 | outw(value, chip->mixer_port + reg); | 396 | outw(value, chip->mixer_io + reg); |
| 301 | } | 397 | } |
| 302 | 398 | ||
| 303 | static inline u16 | 399 | static inline u16 |
| 304 | snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, int reg) | 400 | snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg) |
| 305 | { | 401 | { |
| 306 | return inw(chip->mixer_port + reg); | 402 | return inw(chip->mixer_io + reg); |
| 307 | } | 403 | } |
| 308 | 404 | ||
| 309 | static void | 405 | #define AZF_MUTE_BIT 0x80 |
| 310 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, int reg, int do_mute) | 406 | |
| 407 | static int | ||
| 408 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, | ||
| 409 | unsigned reg, int do_mute | ||
| 410 | ) | ||
| 311 | { | 411 | { |
| 312 | unsigned long portbase = chip->mixer_port + reg + 1; | 412 | unsigned long portbase = chip->mixer_io + reg + 1; |
| 313 | unsigned char oldval; | 413 | int updated; |
| 314 | 414 | ||
| 315 | /* the mute bit is on the *second* (i.e. right) register of a | 415 | /* the mute bit is on the *second* (i.e. right) register of a |
| 316 | * left/right channel setting */ | 416 | * left/right channel setting */ |
| 317 | oldval = inb(portbase); | 417 | updated = snd_azf3328_io_reg_setb(portbase, AZF_MUTE_BIT, do_mute); |
| 318 | if (do_mute) | 418 | |
| 319 | oldval |= 0x80; | 419 | /* indicate whether it was muted before */ |
| 320 | else | 420 | return (do_mute) ? !updated : updated; |
| 321 | oldval &= ~0x80; | ||
| 322 | outb(oldval, portbase); | ||
| 323 | } | 421 | } |
| 324 | 422 | ||
| 325 | static void | 423 | static void |
| 326 | snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg, unsigned char dst_vol_left, unsigned char dst_vol_right, int chan_sel, int delay) | 424 | snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, |
| 425 | unsigned reg, | ||
| 426 | unsigned char dst_vol_left, | ||
| 427 | unsigned char dst_vol_right, | ||
| 428 | int chan_sel, int delay | ||
| 429 | ) | ||
| 327 | { | 430 | { |
| 328 | unsigned long portbase = chip->mixer_port + reg; | 431 | unsigned long portbase = chip->mixer_io + reg; |
| 329 | unsigned char curr_vol_left = 0, curr_vol_right = 0; | 432 | unsigned char curr_vol_left = 0, curr_vol_right = 0; |
| 330 | int left_done = 0, right_done = 0; | 433 | int left_change = 0, right_change = 0; |
| 331 | 434 | ||
| 332 | snd_azf3328_dbgcallenter(); | 435 | snd_azf3328_dbgcallenter(); |
| 333 | if (chan_sel & SET_CHAN_LEFT) | 436 | |
| 437 | if (chan_sel & SET_CHAN_LEFT) { | ||
| 334 | curr_vol_left = inb(portbase + 1); | 438 | curr_vol_left = inb(portbase + 1); |
| 335 | else | 439 | |
| 336 | left_done = 1; | 440 | /* take care of muting flag contained in left channel */ |
| 337 | if (chan_sel & SET_CHAN_RIGHT) | 441 | if (curr_vol_left & AZF_MUTE_BIT) |
| 442 | dst_vol_left |= AZF_MUTE_BIT; | ||
| 443 | else | ||
| 444 | dst_vol_left &= ~AZF_MUTE_BIT; | ||
| 445 | |||
| 446 | left_change = (curr_vol_left > dst_vol_left) ? -1 : 1; | ||
| 447 | } | ||
| 448 | |||
| 449 | if (chan_sel & SET_CHAN_RIGHT) { | ||
| 338 | curr_vol_right = inb(portbase + 0); | 450 | curr_vol_right = inb(portbase + 0); |
| 339 | else | 451 | |
| 340 | right_done = 1; | 452 | right_change = (curr_vol_right > dst_vol_right) ? -1 : 1; |
| 341 | 453 | } | |
| 342 | /* take care of muting flag (0x80) contained in left channel */ | ||
| 343 | if (curr_vol_left & 0x80) | ||
| 344 | dst_vol_left |= 0x80; | ||
| 345 | else | ||
| 346 | dst_vol_left &= ~0x80; | ||
| 347 | 454 | ||
| 348 | do { | 455 | do { |
| 349 | if (!left_done) { | 456 | if (left_change) { |
| 350 | if (curr_vol_left > dst_vol_left) | 457 | if (curr_vol_left != dst_vol_left) { |
| 351 | curr_vol_left--; | 458 | curr_vol_left += left_change; |
| 352 | else | 459 | outb(curr_vol_left, portbase + 1); |
| 353 | if (curr_vol_left < dst_vol_left) | 460 | } else |
| 354 | curr_vol_left++; | 461 | left_change = 0; |
| 355 | else | ||
| 356 | left_done = 1; | ||
| 357 | outb(curr_vol_left, portbase + 1); | ||
| 358 | } | 462 | } |
| 359 | if (!right_done) { | 463 | if (right_change) { |
| 360 | if (curr_vol_right > dst_vol_right) | 464 | if (curr_vol_right != dst_vol_right) { |
| 361 | curr_vol_right--; | 465 | curr_vol_right += right_change; |
| 362 | else | 466 | |
| 363 | if (curr_vol_right < dst_vol_right) | ||
| 364 | curr_vol_right++; | ||
| 365 | else | ||
| 366 | right_done = 1; | ||
| 367 | /* during volume change, the right channel is crackling | 467 | /* during volume change, the right channel is crackling |
| 368 | * somewhat more than the left channel, unfortunately. | 468 | * somewhat more than the left channel, unfortunately. |
| 369 | * This seems to be a hardware issue. */ | 469 | * This seems to be a hardware issue. */ |
| 370 | outb(curr_vol_right, portbase + 0); | 470 | outb(curr_vol_right, portbase + 0); |
| 471 | } else | ||
| 472 | right_change = 0; | ||
| 371 | } | 473 | } |
| 372 | if (delay) | 474 | if (delay) |
| 373 | mdelay(delay); | 475 | mdelay(delay); |
| 374 | } while ((!left_done) || (!right_done)); | 476 | } while ((left_change) || (right_change)); |
| 375 | snd_azf3328_dbgcallleave(); | 477 | snd_azf3328_dbgcallleave(); |
| 376 | } | 478 | } |
| 377 | 479 | ||
| @@ -379,7 +481,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
| 379 | * general mixer element | 481 | * general mixer element |
| 380 | */ | 482 | */ |
| 381 | struct azf3328_mixer_reg { | 483 | struct azf3328_mixer_reg { |
| 382 | unsigned int reg; | 484 | unsigned reg; |
| 383 | unsigned int lchan_shift, rchan_shift; | 485 | unsigned int lchan_shift, rchan_shift; |
| 384 | unsigned int mask; | 486 | unsigned int mask; |
| 385 | unsigned int invert: 1; | 487 | unsigned int invert: 1; |
| @@ -544,13 +646,14 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 544 | "Mix", "Mic" | 646 | "Mix", "Mic" |
| 545 | }; | 647 | }; |
| 546 | static const char * const texts3[] = { | 648 | static const char * const texts3[] = { |
| 547 | "Mic", "CD", "Video", "Aux", | 649 | "Mic", "CD", "Video", "Aux", |
| 548 | "Line", "Mix", "Mix Mono", "Phone" | 650 | "Line", "Mix", "Mix Mono", "Phone" |
| 549 | }; | 651 | }; |
| 550 | static const char * const texts4[] = { | 652 | static const char * const texts4[] = { |
| 551 | "pre 3D", "post 3D" | 653 | "pre 3D", "post 3D" |
| 552 | }; | 654 | }; |
| 553 | struct azf3328_mixer_reg reg; | 655 | struct azf3328_mixer_reg reg; |
| 656 | const char * const *p = NULL; | ||
| 554 | 657 | ||
| 555 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 658 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| 556 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 659 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
| @@ -561,18 +664,20 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 561 | if (reg.reg == IDX_MIXER_ADVCTL2) { | 664 | if (reg.reg == IDX_MIXER_ADVCTL2) { |
| 562 | switch(reg.lchan_shift) { | 665 | switch(reg.lchan_shift) { |
| 563 | case 8: /* modem out sel */ | 666 | case 8: /* modem out sel */ |
| 564 | strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); | 667 | p = texts1; |
| 565 | break; | 668 | break; |
| 566 | case 9: /* mono sel source */ | 669 | case 9: /* mono sel source */ |
| 567 | strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); | 670 | p = texts2; |
| 568 | break; | 671 | break; |
| 569 | case 15: /* PCM Out Path */ | 672 | case 15: /* PCM Out Path */ |
| 570 | strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]); | 673 | p = texts4; |
| 571 | break; | 674 | break; |
| 572 | } | 675 | } |
| 573 | } else | 676 | } else |
| 574 | strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] | 677 | if (reg.reg == IDX_MIXER_REC_SELECT) |
| 575 | ); | 678 | p = texts3; |
| 679 | |||
| 680 | strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]); | ||
| 576 | return 0; | 681 | return 0; |
| 577 | } | 682 | } |
| 578 | 683 | ||
| @@ -583,7 +688,7 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 583 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 688 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
| 584 | struct azf3328_mixer_reg reg; | 689 | struct azf3328_mixer_reg reg; |
| 585 | unsigned short val; | 690 | unsigned short val; |
| 586 | 691 | ||
| 587 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 692 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| 588 | val = snd_azf3328_mixer_inw(chip, reg.reg); | 693 | val = snd_azf3328_mixer_inw(chip, reg.reg); |
| 589 | if (reg.reg == IDX_MIXER_REC_SELECT) { | 694 | if (reg.reg == IDX_MIXER_REC_SELECT) { |
| @@ -605,7 +710,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 605 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 710 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
| 606 | struct azf3328_mixer_reg reg; | 711 | struct azf3328_mixer_reg reg; |
| 607 | unsigned int oreg, nreg, val; | 712 | unsigned int oreg, nreg, val; |
| 608 | 713 | ||
| 609 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 714 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| 610 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); | 715 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); |
| 611 | val = oreg; | 716 | val = oreg; |
| @@ -631,9 +736,11 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 631 | static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { | 736 | static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { |
| 632 | AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), | 737 | AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), |
| 633 | AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), | 738 | AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), |
| 634 | AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), | 739 | AZF3328_MIXER_SWITCH("PCM Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), |
| 635 | AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1), | 740 | AZF3328_MIXER_VOL_STEREO("PCM Playback Volume", |
| 636 | AZF3328_MIXER_SWITCH("Wave 3D Bypass Playback Switch", IDX_MIXER_ADVCTL2, 7, 1), | 741 | IDX_MIXER_WAVEOUT, 0x1f, 1), |
| 742 | AZF3328_MIXER_SWITCH("PCM 3D Bypass Playback Switch", | ||
| 743 | IDX_MIXER_ADVCTL2, 7, 1), | ||
| 637 | AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), | 744 | AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), |
| 638 | AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), | 745 | AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), |
| 639 | AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), | 746 | AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), |
| @@ -717,15 +824,16 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) | |||
| 717 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); | 824 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); |
| 718 | 825 | ||
| 719 | /* mute and zero volume channels */ | 826 | /* mute and zero volume channels */ |
| 720 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); idx++) { | 827 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); ++idx) { |
| 721 | snd_azf3328_mixer_outw(chip, | 828 | snd_azf3328_mixer_outw(chip, |
| 722 | snd_azf3328_init_values[idx][0], | 829 | snd_azf3328_init_values[idx][0], |
| 723 | snd_azf3328_init_values[idx][1]); | 830 | snd_azf3328_init_values[idx][1]); |
| 724 | } | 831 | } |
| 725 | 832 | ||
| 726 | /* add mixer controls */ | 833 | /* add mixer controls */ |
| 727 | sw = snd_azf3328_mixer_controls; | 834 | sw = snd_azf3328_mixer_controls; |
| 728 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); idx++, sw++) { | 835 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); |
| 836 | ++idx, ++sw) { | ||
| 729 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0) | 837 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0) |
| 730 | return err; | 838 | return err; |
| 731 | } | 839 | } |
| @@ -757,9 +865,9 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) | |||
| 757 | } | 865 | } |
| 758 | 866 | ||
| 759 | static void | 867 | static void |
| 760 | snd_azf3328_setfmt(struct snd_azf3328 *chip, | 868 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, |
| 761 | unsigned int reg, | 869 | unsigned reg, |
| 762 | unsigned int bitrate, | 870 | enum azf_freq_t bitrate, |
| 763 | unsigned int format_width, | 871 | unsigned int format_width, |
| 764 | unsigned int channels | 872 | unsigned int channels |
| 765 | ) | 873 | ) |
| @@ -769,24 +877,25 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip, | |||
| 769 | 877 | ||
| 770 | snd_azf3328_dbgcallenter(); | 878 | snd_azf3328_dbgcallenter(); |
| 771 | switch (bitrate) { | 879 | switch (bitrate) { |
| 772 | case 4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; | 880 | case AZF_FREQ_4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; |
| 773 | case 4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; | 881 | case AZF_FREQ_4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; |
| 774 | case 5512: val |= SOUNDFORMAT_FREQ_5510; break; /* the AZF3328 names it "5510" for some strange reason */ | 882 | case AZF_FREQ_5512: |
| 775 | case 6620: val |= SOUNDFORMAT_FREQ_6620; break; | 883 | /* the AZF3328 names it "5510" for some strange reason */ |
| 776 | case 8000: val |= SOUNDFORMAT_FREQ_8000; break; | 884 | val |= SOUNDFORMAT_FREQ_5510; break; |
| 777 | case 9600: val |= SOUNDFORMAT_FREQ_9600; break; | 885 | case AZF_FREQ_6620: val |= SOUNDFORMAT_FREQ_6620; break; |
| 778 | case 11025: val |= SOUNDFORMAT_FREQ_11025; break; | 886 | case AZF_FREQ_8000: val |= SOUNDFORMAT_FREQ_8000; break; |
| 779 | case 13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; | 887 | case AZF_FREQ_9600: val |= SOUNDFORMAT_FREQ_9600; break; |
| 780 | case 16000: val |= SOUNDFORMAT_FREQ_16000; break; | 888 | case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break; |
| 781 | case 22050: val |= SOUNDFORMAT_FREQ_22050; break; | 889 | case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; |
| 782 | case 32000: val |= SOUNDFORMAT_FREQ_32000; break; | 890 | case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break; |
| 783 | case 44100: val |= SOUNDFORMAT_FREQ_44100; break; | 891 | case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break; |
| 784 | case 48000: val |= SOUNDFORMAT_FREQ_48000; break; | 892 | case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break; |
| 785 | case 66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; | ||
| 786 | default: | 893 | default: |
| 787 | snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); | 894 | snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); |
| 788 | val |= SOUNDFORMAT_FREQ_44100; | 895 | /* fall-through */ |
| 789 | break; | 896 | case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break; |
| 897 | case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break; | ||
| 898 | case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; | ||
| 790 | } | 899 | } |
| 791 | /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ | 900 | /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ |
| 792 | /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ | 901 | /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ |
| @@ -805,10 +914,10 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip, | |||
| 805 | val |= SOUNDFORMAT_FLAG_16BIT; | 914 | val |= SOUNDFORMAT_FLAG_16BIT; |
| 806 | 915 | ||
| 807 | spin_lock_irqsave(&chip->reg_lock, flags); | 916 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 808 | 917 | ||
| 809 | /* set bitrate/format */ | 918 | /* set bitrate/format */ |
| 810 | snd_azf3328_codec_outw(chip, reg, val); | 919 | snd_azf3328_codec_outw(chip, reg, val); |
| 811 | 920 | ||
| 812 | /* changing the bitrate/format settings switches off the | 921 | /* changing the bitrate/format settings switches off the |
| 813 | * audio output with an annoying click in case of 8/16bit format change | 922 | * audio output with an annoying click in case of 8/16bit format change |
| 814 | * (maybe shutting down DAC/ADC?), thus immediately | 923 | * (maybe shutting down DAC/ADC?), thus immediately |
| @@ -830,31 +939,95 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip, | |||
| 830 | snd_azf3328_dbgcallleave(); | 939 | snd_azf3328_dbgcallleave(); |
| 831 | } | 940 | } |
| 832 | 941 | ||
| 942 | static inline void | ||
| 943 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, | ||
| 944 | unsigned reg | ||
| 945 | ) | ||
| 946 | { | ||
| 947 | /* choose lowest frequency for low power consumption. | ||
| 948 | * While this will cause louder noise due to rather coarse frequency, | ||
| 949 | * it should never matter since output should always | ||
| 950 | * get disabled properly when idle anyway. */ | ||
| 951 | snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1); | ||
| 952 | } | ||
| 953 | |||
| 954 | static void | ||
| 955 | snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip, | ||
| 956 | unsigned bitmask, | ||
| 957 | int enable | ||
| 958 | ) | ||
| 959 | { | ||
| 960 | if (enable) | ||
| 961 | chip->shadow_reg_codec_6AH &= ~bitmask; | ||
| 962 | else | ||
| 963 | chip->shadow_reg_codec_6AH |= bitmask; | ||
| 964 | snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", | ||
| 965 | bitmask, enable, chip->shadow_reg_codec_6AH); | ||
| 966 | snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH); | ||
| 967 | } | ||
| 968 | |||
| 969 | static inline void | ||
| 970 | snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable) | ||
| 971 | { | ||
| 972 | snd_azf3328_dbgplay("codec_enable %d\n", enable); | ||
| 973 | /* no idea what exactly is being done here, but I strongly assume it's | ||
| 974 | * PM related */ | ||
| 975 | snd_azf3328_codec_reg_6AH_update( | ||
| 976 | chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable | ||
| 977 | ); | ||
| 978 | } | ||
| 979 | |||
| 980 | static void | ||
| 981 | snd_azf3328_codec_activity(struct snd_azf3328 *chip, | ||
| 982 | enum snd_azf3328_stream_index stream_type, | ||
| 983 | int enable | ||
| 984 | ) | ||
| 985 | { | ||
| 986 | int need_change = (chip->audio_stream[stream_type].running != enable); | ||
| 987 | |||
| 988 | snd_azf3328_dbgplay( | ||
| 989 | "codec_activity: type %d, enable %d, need_change %d\n", | ||
| 990 | stream_type, enable, need_change | ||
| 991 | ); | ||
| 992 | if (need_change) { | ||
| 993 | enum snd_azf3328_stream_index other = | ||
| 994 | (stream_type == AZF_PLAYBACK) ? | ||
| 995 | AZF_CAPTURE : AZF_PLAYBACK; | ||
| 996 | /* small check to prevent shutting down the other party | ||
| 997 | * in case it's active */ | ||
| 998 | if ((enable) || !(chip->audio_stream[other].running)) | ||
| 999 | snd_azf3328_codec_enable(chip, enable); | ||
| 1000 | |||
| 1001 | /* ...and adjust clock, too | ||
| 1002 | * (reduce noise and power consumption) */ | ||
| 1003 | if (!enable) | ||
| 1004 | snd_azf3328_codec_setfmt_lowpower( | ||
| 1005 | chip, | ||
| 1006 | chip->audio_stream[stream_type].portbase | ||
| 1007 | + IDX_IO_PLAY_SOUNDFORMAT | ||
| 1008 | ); | ||
| 1009 | } | ||
| 1010 | chip->audio_stream[stream_type].running = enable; | ||
| 1011 | } | ||
| 1012 | |||
| 833 | static void | 1013 | static void |
| 834 | snd_azf3328_setdmaa(struct snd_azf3328 *chip, | 1014 | snd_azf3328_setdmaa(struct snd_azf3328 *chip, |
| 835 | long unsigned int addr, | 1015 | long unsigned int addr, |
| 836 | unsigned int count, | 1016 | unsigned int count, |
| 837 | unsigned int size, | 1017 | unsigned int size, |
| 838 | int do_recording) | 1018 | enum snd_azf3328_stream_index stream_type |
| 1019 | ) | ||
| 839 | { | 1020 | { |
| 840 | unsigned long flags, portbase; | ||
| 841 | unsigned int is_running; | ||
| 842 | |||
| 843 | snd_azf3328_dbgcallenter(); | 1021 | snd_azf3328_dbgcallenter(); |
| 844 | if (do_recording) { | 1022 | if (!chip->audio_stream[stream_type].running) { |
| 845 | /* access capture registers, i.e. skip playback reg section */ | 1023 | /* AZF3328 uses a two buffer pointer DMA playback approach */ |
| 846 | portbase = chip->codec_port + 0x20; | ||
| 847 | is_running = chip->is_recording; | ||
| 848 | } else { | ||
| 849 | /* access the playback register section */ | ||
| 850 | portbase = chip->codec_port + 0x00; | ||
| 851 | is_running = chip->is_playing; | ||
| 852 | } | ||
| 853 | 1024 | ||
| 854 | /* AZF3328 uses a two buffer pointer DMA playback approach */ | 1025 | unsigned long flags, portbase, addr_area2; |
| 855 | if (!is_running) { | 1026 | |
| 856 | unsigned long addr_area2; | 1027 | /* width 32bit (prevent overflow): */ |
| 857 | unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ | 1028 | unsigned long count_areas, count_tmp; |
| 1029 | |||
| 1030 | portbase = chip->audio_stream[stream_type].portbase; | ||
| 858 | count_areas = size/2; | 1031 | count_areas = size/2; |
| 859 | addr_area2 = addr+count_areas; | 1032 | addr_area2 = addr+count_areas; |
| 860 | count_areas--; /* max. index */ | 1033 | count_areas--; /* max. index */ |
| @@ -884,11 +1057,11 @@ snd_azf3328_playback_prepare(struct snd_pcm_substream *substream) | |||
| 884 | 1057 | ||
| 885 | snd_azf3328_dbgcallenter(); | 1058 | snd_azf3328_dbgcallenter(); |
| 886 | #if 0 | 1059 | #if 0 |
| 887 | snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | 1060 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, |
| 888 | runtime->rate, | 1061 | runtime->rate, |
| 889 | snd_pcm_format_width(runtime->format), | 1062 | snd_pcm_format_width(runtime->format), |
| 890 | runtime->channels); | 1063 | runtime->channels); |
| 891 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 0); | 1064 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK); |
| 892 | #endif | 1065 | #endif |
| 893 | snd_azf3328_dbgcallleave(); | 1066 | snd_azf3328_dbgcallleave(); |
| 894 | return 0; | 1067 | return 0; |
| @@ -906,11 +1079,11 @@ snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) | |||
| 906 | 1079 | ||
| 907 | snd_azf3328_dbgcallenter(); | 1080 | snd_azf3328_dbgcallenter(); |
| 908 | #if 0 | 1081 | #if 0 |
| 909 | snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, | 1082 | snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, |
| 910 | runtime->rate, | 1083 | runtime->rate, |
| 911 | snd_pcm_format_width(runtime->format), | 1084 | snd_pcm_format_width(runtime->format), |
| 912 | runtime->channels); | 1085 | runtime->channels); |
| 913 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 1); | 1086 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE); |
| 914 | #endif | 1087 | #endif |
| 915 | snd_azf3328_dbgcallleave(); | 1088 | snd_azf3328_dbgcallleave(); |
| 916 | return 0; | 1089 | return 0; |
| @@ -923,6 +1096,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 923 | struct snd_pcm_runtime *runtime = substream->runtime; | 1096 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 924 | int result = 0; | 1097 | int result = 0; |
| 925 | unsigned int status1; | 1098 | unsigned int status1; |
| 1099 | int previously_muted; | ||
| 926 | 1100 | ||
| 927 | snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); | 1101 | snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); |
| 928 | 1102 | ||
| @@ -930,20 +1104,23 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 930 | case SNDRV_PCM_TRIGGER_START: | 1104 | case SNDRV_PCM_TRIGGER_START: |
| 931 | snd_azf3328_dbgplay("START PLAYBACK\n"); | 1105 | snd_azf3328_dbgplay("START PLAYBACK\n"); |
| 932 | 1106 | ||
| 933 | /* mute WaveOut */ | 1107 | /* mute WaveOut (avoid clicking during setup) */ |
| 934 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1108 | previously_muted = |
| 1109 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | ||
| 935 | 1110 | ||
| 936 | snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | 1111 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, |
| 937 | runtime->rate, | 1112 | runtime->rate, |
| 938 | snd_pcm_format_width(runtime->format), | 1113 | snd_pcm_format_width(runtime->format), |
| 939 | runtime->channels); | 1114 | runtime->channels); |
| 940 | 1115 | ||
| 941 | spin_lock(&chip->reg_lock); | 1116 | spin_lock(&chip->reg_lock); |
| 942 | /* stop playback */ | 1117 | /* first, remember current value: */ |
| 943 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1118 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); |
| 1119 | |||
| 1120 | /* stop playback */ | ||
| 944 | status1 &= ~DMA_RESUME; | 1121 | status1 &= ~DMA_RESUME; |
| 945 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1122 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); |
| 946 | 1123 | ||
| 947 | /* FIXME: clear interrupts or what??? */ | 1124 | /* FIXME: clear interrupts or what??? */ |
| 948 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); | 1125 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); |
| 949 | spin_unlock(&chip->reg_lock); | 1126 | spin_unlock(&chip->reg_lock); |
| @@ -951,7 +1128,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 951 | snd_azf3328_setdmaa(chip, runtime->dma_addr, | 1128 | snd_azf3328_setdmaa(chip, runtime->dma_addr, |
| 952 | snd_pcm_lib_period_bytes(substream), | 1129 | snd_pcm_lib_period_bytes(substream), |
| 953 | snd_pcm_lib_buffer_bytes(substream), | 1130 | snd_pcm_lib_buffer_bytes(substream), |
| 954 | 0); | 1131 | AZF_PLAYBACK); |
| 955 | 1132 | ||
| 956 | spin_lock(&chip->reg_lock); | 1133 | spin_lock(&chip->reg_lock); |
| 957 | #ifdef WIN9X | 1134 | #ifdef WIN9X |
| @@ -978,30 +1155,35 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 978 | DMA_SOMETHING_ELSE); | 1155 | DMA_SOMETHING_ELSE); |
| 979 | #endif | 1156 | #endif |
| 980 | spin_unlock(&chip->reg_lock); | 1157 | spin_unlock(&chip->reg_lock); |
| 1158 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1); | ||
| 981 | 1159 | ||
| 982 | /* now unmute WaveOut */ | 1160 | /* now unmute WaveOut */ |
| 983 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1161 | if (!previously_muted) |
| 1162 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | ||
| 984 | 1163 | ||
| 985 | chip->is_playing = 1; | ||
| 986 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); | 1164 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); |
| 987 | break; | 1165 | break; |
| 988 | case SNDRV_PCM_TRIGGER_RESUME: | 1166 | case SNDRV_PCM_TRIGGER_RESUME: |
| 989 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); | 1167 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); |
| 990 | /* resume playback if we were active */ | 1168 | /* resume playback if we were active */ |
| 991 | if (chip->is_playing) | 1169 | spin_lock(&chip->reg_lock); |
| 1170 | if (chip->audio_stream[AZF_PLAYBACK].running) | ||
| 992 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1171 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, |
| 993 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); | 1172 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); |
| 1173 | spin_unlock(&chip->reg_lock); | ||
| 994 | break; | 1174 | break; |
| 995 | case SNDRV_PCM_TRIGGER_STOP: | 1175 | case SNDRV_PCM_TRIGGER_STOP: |
| 996 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); | 1176 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); |
| 997 | 1177 | ||
| 998 | /* mute WaveOut */ | 1178 | /* mute WaveOut (avoid clicking during setup) */ |
| 999 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1179 | previously_muted = |
| 1180 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | ||
| 1000 | 1181 | ||
| 1001 | spin_lock(&chip->reg_lock); | 1182 | spin_lock(&chip->reg_lock); |
| 1002 | /* stop playback */ | 1183 | /* first, remember current value: */ |
| 1003 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1184 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); |
| 1004 | 1185 | ||
| 1186 | /* stop playback */ | ||
| 1005 | status1 &= ~DMA_RESUME; | 1187 | status1 &= ~DMA_RESUME; |
| 1006 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1188 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); |
| 1007 | 1189 | ||
| @@ -1013,10 +1195,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1013 | status1 &= ~DMA_PLAY_SOMETHING1; | 1195 | status1 &= ~DMA_PLAY_SOMETHING1; |
| 1014 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1196 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); |
| 1015 | spin_unlock(&chip->reg_lock); | 1197 | spin_unlock(&chip->reg_lock); |
| 1016 | 1198 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); | |
| 1199 | |||
| 1017 | /* now unmute WaveOut */ | 1200 | /* now unmute WaveOut */ |
| 1018 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1201 | if (!previously_muted) |
| 1019 | chip->is_playing = 0; | 1202 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); |
| 1203 | |||
| 1020 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); | 1204 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); |
| 1021 | break; | 1205 | break; |
| 1022 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1206 | case SNDRV_PCM_TRIGGER_SUSPEND: |
| @@ -1035,7 +1219,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1035 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | 1219 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); |
| 1036 | return -EINVAL; | 1220 | return -EINVAL; |
| 1037 | } | 1221 | } |
| 1038 | 1222 | ||
| 1039 | snd_azf3328_dbgcallleave(); | 1223 | snd_azf3328_dbgcallleave(); |
| 1040 | return result; | 1224 | return result; |
| 1041 | } | 1225 | } |
| @@ -1057,17 +1241,19 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1057 | 1241 | ||
| 1058 | snd_azf3328_dbgplay("START CAPTURE\n"); | 1242 | snd_azf3328_dbgplay("START CAPTURE\n"); |
| 1059 | 1243 | ||
| 1060 | snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, | 1244 | snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, |
| 1061 | runtime->rate, | 1245 | runtime->rate, |
| 1062 | snd_pcm_format_width(runtime->format), | 1246 | snd_pcm_format_width(runtime->format), |
| 1063 | runtime->channels); | 1247 | runtime->channels); |
| 1064 | 1248 | ||
| 1065 | spin_lock(&chip->reg_lock); | 1249 | spin_lock(&chip->reg_lock); |
| 1066 | /* stop recording */ | 1250 | /* first, remember current value: */ |
| 1067 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); | 1251 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); |
| 1252 | |||
| 1253 | /* stop recording */ | ||
| 1068 | status1 &= ~DMA_RESUME; | 1254 | status1 &= ~DMA_RESUME; |
| 1069 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | 1255 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); |
| 1070 | 1256 | ||
| 1071 | /* FIXME: clear interrupts or what??? */ | 1257 | /* FIXME: clear interrupts or what??? */ |
| 1072 | snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); | 1258 | snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); |
| 1073 | spin_unlock(&chip->reg_lock); | 1259 | spin_unlock(&chip->reg_lock); |
| @@ -1075,7 +1261,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1075 | snd_azf3328_setdmaa(chip, runtime->dma_addr, | 1261 | snd_azf3328_setdmaa(chip, runtime->dma_addr, |
| 1076 | snd_pcm_lib_period_bytes(substream), | 1262 | snd_pcm_lib_period_bytes(substream), |
| 1077 | snd_pcm_lib_buffer_bytes(substream), | 1263 | snd_pcm_lib_buffer_bytes(substream), |
| 1078 | 1); | 1264 | AZF_CAPTURE); |
| 1079 | 1265 | ||
| 1080 | spin_lock(&chip->reg_lock); | 1266 | spin_lock(&chip->reg_lock); |
| 1081 | #ifdef WIN9X | 1267 | #ifdef WIN9X |
| @@ -1102,24 +1288,27 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1102 | DMA_SOMETHING_ELSE); | 1288 | DMA_SOMETHING_ELSE); |
| 1103 | #endif | 1289 | #endif |
| 1104 | spin_unlock(&chip->reg_lock); | 1290 | spin_unlock(&chip->reg_lock); |
| 1291 | snd_azf3328_codec_activity(chip, AZF_CAPTURE, 1); | ||
| 1105 | 1292 | ||
| 1106 | chip->is_recording = 1; | ||
| 1107 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); | 1293 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); |
| 1108 | break; | 1294 | break; |
| 1109 | case SNDRV_PCM_TRIGGER_RESUME: | 1295 | case SNDRV_PCM_TRIGGER_RESUME: |
| 1110 | snd_azf3328_dbgplay("RESUME CAPTURE\n"); | 1296 | snd_azf3328_dbgplay("RESUME CAPTURE\n"); |
| 1111 | /* resume recording if we were active */ | 1297 | /* resume recording if we were active */ |
| 1112 | if (chip->is_recording) | 1298 | spin_lock(&chip->reg_lock); |
| 1299 | if (chip->audio_stream[AZF_CAPTURE].running) | ||
| 1113 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | 1300 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, |
| 1114 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); | 1301 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); |
| 1302 | spin_unlock(&chip->reg_lock); | ||
| 1115 | break; | 1303 | break; |
| 1116 | case SNDRV_PCM_TRIGGER_STOP: | 1304 | case SNDRV_PCM_TRIGGER_STOP: |
| 1117 | snd_azf3328_dbgplay("STOP CAPTURE\n"); | 1305 | snd_azf3328_dbgplay("STOP CAPTURE\n"); |
| 1118 | 1306 | ||
| 1119 | spin_lock(&chip->reg_lock); | 1307 | spin_lock(&chip->reg_lock); |
| 1120 | /* stop recording */ | 1308 | /* first, remember current value: */ |
| 1121 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); | 1309 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); |
| 1122 | 1310 | ||
| 1311 | /* stop recording */ | ||
| 1123 | status1 &= ~DMA_RESUME; | 1312 | status1 &= ~DMA_RESUME; |
| 1124 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | 1313 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); |
| 1125 | 1314 | ||
| @@ -1129,8 +1318,8 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1129 | status1 &= ~DMA_PLAY_SOMETHING1; | 1318 | status1 &= ~DMA_PLAY_SOMETHING1; |
| 1130 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | 1319 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); |
| 1131 | spin_unlock(&chip->reg_lock); | 1320 | spin_unlock(&chip->reg_lock); |
| 1132 | 1321 | snd_azf3328_codec_activity(chip, AZF_CAPTURE, 0); | |
| 1133 | chip->is_recording = 0; | 1322 | |
| 1134 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); | 1323 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); |
| 1135 | break; | 1324 | break; |
| 1136 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1325 | case SNDRV_PCM_TRIGGER_SUSPEND: |
| @@ -1149,7 +1338,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1149 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | 1338 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); |
| 1150 | return -EINVAL; | 1339 | return -EINVAL; |
| 1151 | } | 1340 | } |
| 1152 | 1341 | ||
| 1153 | snd_azf3328_dbgcallleave(); | 1342 | snd_azf3328_dbgcallleave(); |
| 1154 | return result; | 1343 | return result; |
| 1155 | } | 1344 | } |
| @@ -1162,11 +1351,11 @@ snd_azf3328_playback_pointer(struct snd_pcm_substream *substream) | |||
| 1162 | snd_pcm_uframes_t frmres; | 1351 | snd_pcm_uframes_t frmres; |
| 1163 | 1352 | ||
| 1164 | #ifdef QUERY_HARDWARE | 1353 | #ifdef QUERY_HARDWARE |
| 1165 | bufptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_START_1); | 1354 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1); |
| 1166 | #else | 1355 | #else |
| 1167 | bufptr = substream->runtime->dma_addr; | 1356 | bufptr = substream->runtime->dma_addr; |
| 1168 | #endif | 1357 | #endif |
| 1169 | result = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS); | 1358 | result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS); |
| 1170 | 1359 | ||
| 1171 | /* calculate offset */ | 1360 | /* calculate offset */ |
| 1172 | result -= bufptr; | 1361 | result -= bufptr; |
| @@ -1183,11 +1372,11 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) | |||
| 1183 | snd_pcm_uframes_t frmres; | 1372 | snd_pcm_uframes_t frmres; |
| 1184 | 1373 | ||
| 1185 | #ifdef QUERY_HARDWARE | 1374 | #ifdef QUERY_HARDWARE |
| 1186 | bufptr = inl(chip->codec_port+IDX_IO_REC_DMA_START_1); | 1375 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1); |
| 1187 | #else | 1376 | #else |
| 1188 | bufptr = substream->runtime->dma_addr; | 1377 | bufptr = substream->runtime->dma_addr; |
| 1189 | #endif | 1378 | #endif |
| 1190 | result = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS); | 1379 | result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS); |
| 1191 | 1380 | ||
| 1192 | /* calculate offset */ | 1381 | /* calculate offset */ |
| 1193 | result -= bufptr; | 1382 | result -= bufptr; |
| @@ -1196,27 +1385,241 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) | |||
| 1196 | return frmres; | 1385 | return frmres; |
| 1197 | } | 1386 | } |
| 1198 | 1387 | ||
| 1388 | /******************************************************************/ | ||
| 1389 | |||
| 1390 | #ifdef SUPPORT_GAMEPORT | ||
| 1391 | static inline void | ||
| 1392 | snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) | ||
| 1393 | { | ||
| 1394 | snd_azf3328_io_reg_setb( | ||
| 1395 | chip->game_io+IDX_GAME_HWCONFIG, | ||
| 1396 | GAME_HWCFG_IRQ_ENABLE, | ||
| 1397 | enable | ||
| 1398 | ); | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | static inline void | ||
| 1402 | snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) | ||
| 1403 | { | ||
| 1404 | snd_azf3328_io_reg_setb( | ||
| 1405 | chip->game_io+IDX_GAME_HWCONFIG, | ||
| 1406 | GAME_HWCFG_LEGACY_ADDRESS_ENABLE, | ||
| 1407 | enable | ||
| 1408 | ); | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | static inline void | ||
| 1412 | snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable) | ||
| 1413 | { | ||
| 1414 | snd_azf3328_codec_reg_6AH_update( | ||
| 1415 | chip, IO_6A_SOMETHING2_GAMEPORT, enable | ||
| 1416 | ); | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | static inline void | ||
| 1420 | snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) | ||
| 1421 | { | ||
| 1422 | /* | ||
| 1423 | * skeleton handler only | ||
| 1424 | * (we do not want axis reading in interrupt handler - too much load!) | ||
| 1425 | */ | ||
| 1426 | snd_azf3328_dbggame("gameport irq\n"); | ||
| 1427 | |||
| 1428 | /* this should ACK the gameport IRQ properly, hopefully. */ | ||
| 1429 | snd_azf3328_game_inw(chip, IDX_GAME_AXIS_VALUE); | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | static int | ||
| 1433 | snd_azf3328_gameport_open(struct gameport *gameport, int mode) | ||
| 1434 | { | ||
| 1435 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | ||
| 1436 | int res; | ||
| 1437 | |||
| 1438 | snd_azf3328_dbggame("gameport_open, mode %d\n", mode); | ||
| 1439 | switch (mode) { | ||
| 1440 | case GAMEPORT_MODE_COOKED: | ||
| 1441 | case GAMEPORT_MODE_RAW: | ||
| 1442 | res = 0; | ||
| 1443 | break; | ||
| 1444 | default: | ||
| 1445 | res = -1; | ||
| 1446 | break; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); | ||
| 1450 | |||
| 1451 | return res; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | static void | ||
| 1455 | snd_azf3328_gameport_close(struct gameport *gameport) | ||
| 1456 | { | ||
| 1457 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | ||
| 1458 | |||
| 1459 | snd_azf3328_dbggame("gameport_close\n"); | ||
| 1460 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | static int | ||
| 1464 | snd_azf3328_gameport_cooked_read(struct gameport *gameport, | ||
| 1465 | int *axes, | ||
| 1466 | int *buttons | ||
| 1467 | ) | ||
| 1468 | { | ||
| 1469 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | ||
| 1470 | int i; | ||
| 1471 | u8 val; | ||
| 1472 | unsigned long flags; | ||
| 1473 | |||
| 1474 | snd_assert(chip, return 0); | ||
| 1475 | |||
| 1476 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
| 1477 | val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE); | ||
| 1478 | *buttons = (~(val) >> 4) & 0xf; | ||
| 1479 | |||
| 1480 | /* ok, this one is a bit dirty: cooked_read is being polled by a timer, | ||
| 1481 | * thus we're atomic and cannot actively wait in here | ||
| 1482 | * (which would be useful for us since it probably would be better | ||
| 1483 | * to trigger a measurement in here, then wait a short amount of | ||
| 1484 | * time until it's finished, then read values of _this_ measurement). | ||
| 1485 | * | ||
| 1486 | * Thus we simply resort to reading values if they're available already | ||
| 1487 | * and trigger the next measurement. | ||
| 1488 | */ | ||
| 1489 | |||
| 1490 | val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); | ||
| 1491 | if (val & GAME_AXES_SAMPLING_READY) { | ||
| 1492 | for (i = 0; i < 4; ++i) { | ||
| 1493 | /* configure the axis to read */ | ||
| 1494 | val = (i << 4) | 0x0f; | ||
| 1495 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); | ||
| 1496 | |||
| 1497 | chip->axes[i] = snd_azf3328_game_inw( | ||
| 1498 | chip, IDX_GAME_AXIS_VALUE | ||
| 1499 | ); | ||
| 1500 | } | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | /* trigger next axes sampling, to be evaluated the next time we | ||
| 1504 | * enter this function */ | ||
| 1505 | |||
| 1506 | /* for some very, very strange reason we cannot enable | ||
| 1507 | * Measurement Ready monitoring for all axes here, | ||
| 1508 | * at least not when only one joystick connected */ | ||
| 1509 | val = 0x03; /* we're able to monitor axes 1 and 2 only */ | ||
| 1510 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); | ||
| 1511 | |||
| 1512 | snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); | ||
| 1513 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
| 1514 | |||
| 1515 | for (i = 0; i < 4; i++) { | ||
| 1516 | axes[i] = chip->axes[i]; | ||
| 1517 | if (axes[i] == 0xffff) | ||
| 1518 | axes[i] = -1; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | snd_azf3328_dbggame("cooked_read: axes %d %d %d %d buttons %d\n", | ||
| 1522 | axes[0], axes[1], axes[2], axes[3], *buttons | ||
| 1523 | ); | ||
| 1524 | |||
| 1525 | return 0; | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | static int __devinit | ||
| 1529 | snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) | ||
| 1530 | { | ||
| 1531 | struct gameport *gp; | ||
| 1532 | |||
| 1533 | chip->gameport = gp = gameport_allocate_port(); | ||
| 1534 | if (!gp) { | ||
| 1535 | printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n"); | ||
| 1536 | return -ENOMEM; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | gameport_set_name(gp, "AZF3328 Gameport"); | ||
| 1540 | gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); | ||
| 1541 | gameport_set_dev_parent(gp, &chip->pci->dev); | ||
| 1542 | gp->io = chip->game_io; | ||
| 1543 | gameport_set_port_data(gp, chip); | ||
| 1544 | |||
| 1545 | gp->open = snd_azf3328_gameport_open; | ||
| 1546 | gp->close = snd_azf3328_gameport_close; | ||
| 1547 | gp->fuzz = 16; /* seems ok */ | ||
| 1548 | gp->cooked_read = snd_azf3328_gameport_cooked_read; | ||
| 1549 | |||
| 1550 | /* DISABLE legacy address: we don't need it! */ | ||
| 1551 | snd_azf3328_gameport_legacy_address_enable(chip, 0); | ||
| 1552 | |||
| 1553 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | ||
| 1554 | |||
| 1555 | gameport_register_port(chip->gameport); | ||
| 1556 | |||
| 1557 | return 0; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | static void | ||
| 1561 | snd_azf3328_gameport_free(struct snd_azf3328 *chip) | ||
| 1562 | { | ||
| 1563 | if (chip->gameport) { | ||
| 1564 | gameport_unregister_port(chip->gameport); | ||
| 1565 | chip->gameport = NULL; | ||
| 1566 | } | ||
| 1567 | snd_azf3328_gameport_irq_enable(chip, 0); | ||
| 1568 | } | ||
| 1569 | #else | ||
| 1570 | static inline int | ||
| 1571 | snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) { return -ENOSYS; } | ||
| 1572 | static inline void | ||
| 1573 | snd_azf3328_gameport_free(struct snd_azf3328 *chip) { } | ||
| 1574 | static inline void | ||
| 1575 | snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) | ||
| 1576 | { | ||
| 1577 | printk(KERN_WARNING "huh, game port IRQ occurred!?\n"); | ||
| 1578 | } | ||
| 1579 | #endif /* SUPPORT_GAMEPORT */ | ||
| 1580 | |||
| 1581 | /******************************************************************/ | ||
| 1582 | |||
| 1583 | static inline void | ||
| 1584 | snd_azf3328_irq_log_unknown_type(u8 which) | ||
| 1585 | { | ||
| 1586 | snd_azf3328_dbgplay( | ||
| 1587 | "azt3328: unknown IRQ type (%x) occurred, please report!\n", | ||
| 1588 | which | ||
| 1589 | ); | ||
| 1590 | } | ||
| 1591 | |||
| 1199 | static irqreturn_t | 1592 | static irqreturn_t |
| 1200 | snd_azf3328_interrupt(int irq, void *dev_id) | 1593 | snd_azf3328_interrupt(int irq, void *dev_id) |
| 1201 | { | 1594 | { |
| 1202 | struct snd_azf3328 *chip = dev_id; | 1595 | struct snd_azf3328 *chip = dev_id; |
| 1203 | u8 status, which; | 1596 | u8 status, which; |
| 1597 | #if DEBUG_PLAY_REC | ||
| 1204 | static unsigned long irq_count; | 1598 | static unsigned long irq_count; |
| 1599 | #endif | ||
| 1205 | 1600 | ||
| 1206 | status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); | 1601 | status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); |
| 1207 | 1602 | ||
| 1208 | /* fast path out, to ease interrupt sharing */ | 1603 | /* fast path out, to ease interrupt sharing */ |
| 1209 | if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_TIMER))) | 1604 | if (!(status & |
| 1605 | (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) | ||
| 1606 | )) | ||
| 1210 | return IRQ_NONE; /* must be interrupt for another device */ | 1607 | return IRQ_NONE; /* must be interrupt for another device */ |
| 1211 | 1608 | ||
| 1212 | snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", | 1609 | snd_azf3328_dbgplay( |
| 1213 | irq_count, | 1610 | "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, " |
| 1214 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), | 1611 | "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", |
| 1215 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), | 1612 | irq_count++ /* debug-only */, |
| 1216 | status); | 1613 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), |
| 1217 | 1614 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), | |
| 1615 | status | ||
| 1616 | ); | ||
| 1617 | |||
| 1218 | if (status & IRQ_TIMER) { | 1618 | if (status & IRQ_TIMER) { |
| 1219 | /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ | 1619 | /* snd_azf3328_dbgplay("timer %ld\n", |
| 1620 | snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) | ||
| 1621 | & TIMER_VALUE_MASK | ||
| 1622 | ); */ | ||
| 1220 | if (chip->timer) | 1623 | if (chip->timer) |
| 1221 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | 1624 | snd_timer_interrupt(chip->timer, chip->timer->sticks); |
| 1222 | /* ACK timer */ | 1625 | /* ACK timer */ |
| @@ -1232,15 +1635,20 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
| 1232 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); | 1635 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); |
| 1233 | spin_unlock(&chip->reg_lock); | 1636 | spin_unlock(&chip->reg_lock); |
| 1234 | 1637 | ||
| 1235 | if (chip->pcm && chip->playback_substream) { | 1638 | if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) { |
| 1236 | snd_pcm_period_elapsed(chip->playback_substream); | 1639 | snd_pcm_period_elapsed( |
| 1640 | chip->audio_stream[AZF_PLAYBACK].substream | ||
| 1641 | ); | ||
| 1237 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", | 1642 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", |
| 1238 | which, | 1643 | which, |
| 1239 | inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); | 1644 | snd_azf3328_codec_inl( |
| 1645 | chip, IDX_IO_PLAY_DMA_CURRPOS | ||
| 1646 | ) | ||
| 1647 | ); | ||
| 1240 | } else | 1648 | } else |
| 1241 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1649 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); |
| 1242 | if (which & IRQ_PLAY_SOMETHING) | 1650 | if (which & IRQ_PLAY_SOMETHING) |
| 1243 | snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); | 1651 | snd_azf3328_irq_log_unknown_type(which); |
| 1244 | } | 1652 | } |
| 1245 | if (status & IRQ_RECORDING) { | 1653 | if (status & IRQ_RECORDING) { |
| 1246 | spin_lock(&chip->reg_lock); | 1654 | spin_lock(&chip->reg_lock); |
| @@ -1249,16 +1657,23 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
| 1249 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); | 1657 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); |
| 1250 | spin_unlock(&chip->reg_lock); | 1658 | spin_unlock(&chip->reg_lock); |
| 1251 | 1659 | ||
| 1252 | if (chip->pcm && chip->capture_substream) { | 1660 | if (chip->pcm && chip->audio_stream[AZF_CAPTURE].substream) { |
| 1253 | snd_pcm_period_elapsed(chip->capture_substream); | 1661 | snd_pcm_period_elapsed( |
| 1662 | chip->audio_stream[AZF_CAPTURE].substream | ||
| 1663 | ); | ||
| 1254 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", | 1664 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", |
| 1255 | which, | 1665 | which, |
| 1256 | inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); | 1666 | snd_azf3328_codec_inl( |
| 1667 | chip, IDX_IO_REC_DMA_CURRPOS | ||
| 1668 | ) | ||
| 1669 | ); | ||
| 1257 | } else | 1670 | } else |
| 1258 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1671 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); |
| 1259 | if (which & IRQ_REC_SOMETHING) | 1672 | if (which & IRQ_REC_SOMETHING) |
| 1260 | snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); | 1673 | snd_azf3328_irq_log_unknown_type(which); |
| 1261 | } | 1674 | } |
| 1675 | if (status & IRQ_GAMEPORT) | ||
| 1676 | snd_azf3328_gameport_interrupt(chip); | ||
| 1262 | /* MPU401 has less critical IRQ requirements | 1677 | /* MPU401 has less critical IRQ requirements |
| 1263 | * than timer and playback/recording, right? */ | 1678 | * than timer and playback/recording, right? */ |
| 1264 | if (status & IRQ_MPU401) { | 1679 | if (status & IRQ_MPU401) { |
| @@ -1268,7 +1683,6 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
| 1268 | * If so, then I don't know how... */ | 1683 | * If so, then I don't know how... */ |
| 1269 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); | 1684 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); |
| 1270 | } | 1685 | } |
| 1271 | irq_count++; | ||
| 1272 | return IRQ_HANDLED; | 1686 | return IRQ_HANDLED; |
| 1273 | } | 1687 | } |
| 1274 | 1688 | ||
| @@ -1287,8 +1701,8 @@ static const struct snd_pcm_hardware snd_azf3328_playback = | |||
| 1287 | .rates = SNDRV_PCM_RATE_5512 | | 1701 | .rates = SNDRV_PCM_RATE_5512 | |
| 1288 | SNDRV_PCM_RATE_8000_48000 | | 1702 | SNDRV_PCM_RATE_8000_48000 | |
| 1289 | SNDRV_PCM_RATE_KNOT, | 1703 | SNDRV_PCM_RATE_KNOT, |
| 1290 | .rate_min = 4000, | 1704 | .rate_min = AZF_FREQ_4000, |
| 1291 | .rate_max = 66200, | 1705 | .rate_max = AZF_FREQ_66200, |
| 1292 | .channels_min = 1, | 1706 | .channels_min = 1, |
| 1293 | .channels_max = 2, | 1707 | .channels_max = 2, |
| 1294 | .buffer_bytes_max = 65536, | 1708 | .buffer_bytes_max = 65536, |
| @@ -1315,8 +1729,8 @@ static const struct snd_pcm_hardware snd_azf3328_capture = | |||
| 1315 | .rates = SNDRV_PCM_RATE_5512 | | 1729 | .rates = SNDRV_PCM_RATE_5512 | |
| 1316 | SNDRV_PCM_RATE_8000_48000 | | 1730 | SNDRV_PCM_RATE_8000_48000 | |
| 1317 | SNDRV_PCM_RATE_KNOT, | 1731 | SNDRV_PCM_RATE_KNOT, |
| 1318 | .rate_min = 4000, | 1732 | .rate_min = AZF_FREQ_4000, |
| 1319 | .rate_max = 66200, | 1733 | .rate_max = AZF_FREQ_66200, |
| 1320 | .channels_min = 1, | 1734 | .channels_min = 1, |
| 1321 | .channels_max = 2, | 1735 | .channels_max = 2, |
| 1322 | .buffer_bytes_max = 65536, | 1736 | .buffer_bytes_max = 65536, |
| @@ -1329,10 +1743,24 @@ static const struct snd_pcm_hardware snd_azf3328_capture = | |||
| 1329 | 1743 | ||
| 1330 | 1744 | ||
| 1331 | static unsigned int snd_azf3328_fixed_rates[] = { | 1745 | static unsigned int snd_azf3328_fixed_rates[] = { |
| 1332 | 4000, 4800, 5512, 6620, 8000, 9600, 11025, 13240, 16000, 22050, 32000, | 1746 | AZF_FREQ_4000, |
| 1333 | 44100, 48000, 66200 }; | 1747 | AZF_FREQ_4800, |
| 1748 | AZF_FREQ_5512, | ||
| 1749 | AZF_FREQ_6620, | ||
| 1750 | AZF_FREQ_8000, | ||
| 1751 | AZF_FREQ_9600, | ||
| 1752 | AZF_FREQ_11025, | ||
| 1753 | AZF_FREQ_13240, | ||
| 1754 | AZF_FREQ_16000, | ||
| 1755 | AZF_FREQ_22050, | ||
| 1756 | AZF_FREQ_32000, | ||
| 1757 | AZF_FREQ_44100, | ||
| 1758 | AZF_FREQ_48000, | ||
| 1759 | AZF_FREQ_66200 | ||
| 1760 | }; | ||
| 1761 | |||
| 1334 | static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { | 1762 | static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { |
| 1335 | .count = ARRAY_SIZE(snd_azf3328_fixed_rates), | 1763 | .count = ARRAY_SIZE(snd_azf3328_fixed_rates), |
| 1336 | .list = snd_azf3328_fixed_rates, | 1764 | .list = snd_azf3328_fixed_rates, |
| 1337 | .mask = 0, | 1765 | .mask = 0, |
| 1338 | }; | 1766 | }; |
| @@ -1346,7 +1774,7 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream) | |||
| 1346 | struct snd_pcm_runtime *runtime = substream->runtime; | 1774 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1347 | 1775 | ||
| 1348 | snd_azf3328_dbgcallenter(); | 1776 | snd_azf3328_dbgcallenter(); |
| 1349 | chip->playback_substream = substream; | 1777 | chip->audio_stream[AZF_PLAYBACK].substream = substream; |
| 1350 | runtime->hw = snd_azf3328_playback; | 1778 | runtime->hw = snd_azf3328_playback; |
| 1351 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1779 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
| 1352 | &snd_azf3328_hw_constraints_rates); | 1780 | &snd_azf3328_hw_constraints_rates); |
| @@ -1361,7 +1789,7 @@ snd_azf3328_capture_open(struct snd_pcm_substream *substream) | |||
| 1361 | struct snd_pcm_runtime *runtime = substream->runtime; | 1789 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1362 | 1790 | ||
| 1363 | snd_azf3328_dbgcallenter(); | 1791 | snd_azf3328_dbgcallenter(); |
| 1364 | chip->capture_substream = substream; | 1792 | chip->audio_stream[AZF_CAPTURE].substream = substream; |
| 1365 | runtime->hw = snd_azf3328_capture; | 1793 | runtime->hw = snd_azf3328_capture; |
| 1366 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1794 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
| 1367 | &snd_azf3328_hw_constraints_rates); | 1795 | &snd_azf3328_hw_constraints_rates); |
| @@ -1375,7 +1803,7 @@ snd_azf3328_playback_close(struct snd_pcm_substream *substream) | |||
| 1375 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1803 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
| 1376 | 1804 | ||
| 1377 | snd_azf3328_dbgcallenter(); | 1805 | snd_azf3328_dbgcallenter(); |
| 1378 | chip->playback_substream = NULL; | 1806 | chip->audio_stream[AZF_PLAYBACK].substream = NULL; |
| 1379 | snd_azf3328_dbgcallleave(); | 1807 | snd_azf3328_dbgcallleave(); |
| 1380 | return 0; | 1808 | return 0; |
| 1381 | } | 1809 | } |
| @@ -1386,7 +1814,7 @@ snd_azf3328_capture_close(struct snd_pcm_substream *substream) | |||
| 1386 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1814 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
| 1387 | 1815 | ||
| 1388 | snd_azf3328_dbgcallenter(); | 1816 | snd_azf3328_dbgcallenter(); |
| 1389 | chip->capture_substream = NULL; | 1817 | chip->audio_stream[AZF_CAPTURE].substream = NULL; |
| 1390 | snd_azf3328_dbgcallleave(); | 1818 | snd_azf3328_dbgcallleave(); |
| 1391 | return 0; | 1819 | return 0; |
| 1392 | } | 1820 | } |
| @@ -1441,102 +1869,8 @@ snd_azf3328_pcm(struct snd_azf3328 *chip, int device) | |||
| 1441 | 1869 | ||
| 1442 | /******************************************************************/ | 1870 | /******************************************************************/ |
| 1443 | 1871 | ||
| 1444 | #ifdef SUPPORT_JOYSTICK | 1872 | /*** NOTE: the physical timer resolution actually is 1024000 ticks per second |
| 1445 | static int __devinit | 1873 | *** (probably derived from main crystal via a divider of 24), |
| 1446 | snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) | ||
| 1447 | { | ||
| 1448 | struct gameport *gp; | ||
| 1449 | struct resource *r; | ||
| 1450 | |||
| 1451 | if (!joystick[dev]) | ||
| 1452 | return -ENODEV; | ||
| 1453 | |||
| 1454 | if (!(r = request_region(0x200, 8, "AZF3328 gameport"))) { | ||
| 1455 | printk(KERN_WARNING "azt3328: cannot reserve joystick ports\n"); | ||
| 1456 | return -EBUSY; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | chip->gameport = gp = gameport_allocate_port(); | ||
| 1460 | if (!gp) { | ||
| 1461 | printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n"); | ||
| 1462 | release_and_free_resource(r); | ||
| 1463 | return -ENOMEM; | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | gameport_set_name(gp, "AZF3328 Gameport"); | ||
| 1467 | gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); | ||
| 1468 | gameport_set_dev_parent(gp, &chip->pci->dev); | ||
| 1469 | gp->io = 0x200; | ||
| 1470 | gameport_set_port_data(gp, r); | ||
| 1471 | |||
| 1472 | snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, | ||
| 1473 | snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY); | ||
| 1474 | |||
| 1475 | gameport_register_port(chip->gameport); | ||
| 1476 | |||
| 1477 | return 0; | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | static void | ||
| 1481 | snd_azf3328_free_joystick(struct snd_azf3328 *chip) | ||
| 1482 | { | ||
| 1483 | if (chip->gameport) { | ||
| 1484 | struct resource *r = gameport_get_port_data(chip->gameport); | ||
| 1485 | |||
| 1486 | gameport_unregister_port(chip->gameport); | ||
| 1487 | chip->gameport = NULL; | ||
| 1488 | /* disable gameport */ | ||
| 1489 | snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, | ||
| 1490 | snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); | ||
| 1491 | release_and_free_resource(r); | ||
| 1492 | } | ||
| 1493 | } | ||
| 1494 | #else | ||
| 1495 | static inline int | ||
| 1496 | snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) { return -ENOSYS; } | ||
| 1497 | static inline void | ||
| 1498 | snd_azf3328_free_joystick(struct snd_azf3328 *chip) { } | ||
| 1499 | #endif | ||
| 1500 | |||
| 1501 | /******************************************************************/ | ||
| 1502 | |||
| 1503 | static int | ||
| 1504 | snd_azf3328_free(struct snd_azf3328 *chip) | ||
| 1505 | { | ||
| 1506 | if (chip->irq < 0) | ||
| 1507 | goto __end_hw; | ||
| 1508 | |||
| 1509 | /* reset (close) mixer */ | ||
| 1510 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */ | ||
| 1511 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); | ||
| 1512 | |||
| 1513 | /* interrupt setup - mask everything (FIXME!) */ | ||
| 1514 | /* well, at least we know how to disable the timer IRQ */ | ||
| 1515 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); | ||
| 1516 | |||
| 1517 | if (chip->irq >= 0) | ||
| 1518 | synchronize_irq(chip->irq); | ||
| 1519 | __end_hw: | ||
| 1520 | snd_azf3328_free_joystick(chip); | ||
| 1521 | if (chip->irq >= 0) | ||
| 1522 | free_irq(chip->irq, chip); | ||
| 1523 | pci_release_regions(chip->pci); | ||
| 1524 | pci_disable_device(chip->pci); | ||
| 1525 | |||
| 1526 | kfree(chip); | ||
| 1527 | return 0; | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | static int | ||
| 1531 | snd_azf3328_dev_free(struct snd_device *device) | ||
| 1532 | { | ||
| 1533 | struct snd_azf3328 *chip = device->device_data; | ||
| 1534 | return snd_azf3328_free(chip); | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | /******************************************************************/ | ||
| 1538 | |||
| 1539 | /*** NOTE: the physical timer resolution actually is 1024000 ticks per second, | ||
| 1540 | *** but announcing those attributes to user-space would make programs | 1874 | *** but announcing those attributes to user-space would make programs |
| 1541 | *** configure the timer to a 1 tick value, resulting in an absolutely fatal | 1875 | *** configure the timer to a 1 tick value, resulting in an absolutely fatal |
| 1542 | *** timer IRQ storm. | 1876 | *** timer IRQ storm. |
| @@ -1564,7 +1898,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) | |||
| 1564 | delay = 49; /* minimum time is 49 ticks */ | 1898 | delay = 49; /* minimum time is 49 ticks */ |
| 1565 | } | 1899 | } |
| 1566 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); | 1900 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); |
| 1567 | delay |= TIMER_ENABLE_COUNTDOWN | TIMER_ENABLE_IRQ; | 1901 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; |
| 1568 | spin_lock_irqsave(&chip->reg_lock, flags); | 1902 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 1569 | snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); | 1903 | snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); |
| 1570 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1904 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| @@ -1582,7 +1916,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer) | |||
| 1582 | chip = snd_timer_chip(timer); | 1916 | chip = snd_timer_chip(timer); |
| 1583 | spin_lock_irqsave(&chip->reg_lock, flags); | 1917 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 1584 | /* disable timer countdown and interrupt */ | 1918 | /* disable timer countdown and interrupt */ |
| 1585 | /* FIXME: should we write TIMER_ACK_IRQ here? */ | 1919 | /* FIXME: should we write TIMER_IRQ_ACK here? */ |
| 1586 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); | 1920 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); |
| 1587 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1921 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1588 | snd_azf3328_dbgcallleave(); | 1922 | snd_azf3328_dbgcallleave(); |
| @@ -1626,9 +1960,10 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) | |||
| 1626 | 1960 | ||
| 1627 | snd_azf3328_timer_hw.resolution *= seqtimer_scaling; | 1961 | snd_azf3328_timer_hw.resolution *= seqtimer_scaling; |
| 1628 | snd_azf3328_timer_hw.ticks /= seqtimer_scaling; | 1962 | snd_azf3328_timer_hw.ticks /= seqtimer_scaling; |
| 1629 | if ((err = snd_timer_new(chip->card, "AZF3328", &tid, &timer)) < 0) { | 1963 | |
| 1964 | err = snd_timer_new(chip->card, "AZF3328", &tid, &timer); | ||
| 1965 | if (err < 0) | ||
| 1630 | goto out; | 1966 | goto out; |
| 1631 | } | ||
| 1632 | 1967 | ||
| 1633 | strcpy(timer->name, "AZF3328 timer"); | 1968 | strcpy(timer->name, "AZF3328 timer"); |
| 1634 | timer->private_data = chip; | 1969 | timer->private_data = chip; |
| @@ -1636,6 +1971,8 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) | |||
| 1636 | 1971 | ||
| 1637 | chip->timer = timer; | 1972 | chip->timer = timer; |
| 1638 | 1973 | ||
| 1974 | snd_azf3328_timer_stop(timer); | ||
| 1975 | |||
| 1639 | err = 0; | 1976 | err = 0; |
| 1640 | 1977 | ||
| 1641 | out: | 1978 | out: |
| @@ -1645,10 +1982,44 @@ out: | |||
| 1645 | 1982 | ||
| 1646 | /******************************************************************/ | 1983 | /******************************************************************/ |
| 1647 | 1984 | ||
| 1985 | static int | ||
| 1986 | snd_azf3328_free(struct snd_azf3328 *chip) | ||
| 1987 | { | ||
| 1988 | if (chip->irq < 0) | ||
| 1989 | goto __end_hw; | ||
| 1990 | |||
| 1991 | /* reset (close) mixer: | ||
| 1992 | * first mute master volume, then reset | ||
| 1993 | */ | ||
| 1994 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | ||
| 1995 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); | ||
| 1996 | |||
| 1997 | snd_azf3328_timer_stop(chip->timer); | ||
| 1998 | snd_azf3328_gameport_free(chip); | ||
| 1999 | |||
| 2000 | if (chip->irq >= 0) | ||
| 2001 | synchronize_irq(chip->irq); | ||
| 2002 | __end_hw: | ||
| 2003 | if (chip->irq >= 0) | ||
| 2004 | free_irq(chip->irq, chip); | ||
| 2005 | pci_release_regions(chip->pci); | ||
| 2006 | pci_disable_device(chip->pci); | ||
| 2007 | |||
| 2008 | kfree(chip); | ||
| 2009 | return 0; | ||
| 2010 | } | ||
| 2011 | |||
| 2012 | static int | ||
| 2013 | snd_azf3328_dev_free(struct snd_device *device) | ||
| 2014 | { | ||
| 2015 | struct snd_azf3328 *chip = device->device_data; | ||
| 2016 | return snd_azf3328_free(chip); | ||
| 2017 | } | ||
| 2018 | |||
| 1648 | #if 0 | 2019 | #if 0 |
| 1649 | /* check whether a bit can be modified */ | 2020 | /* check whether a bit can be modified */ |
| 1650 | static void | 2021 | static void |
| 1651 | snd_azf3328_test_bit(unsigned int reg, int bit) | 2022 | snd_azf3328_test_bit(unsigned unsigned reg, int bit) |
| 1652 | { | 2023 | { |
| 1653 | unsigned char val, valoff, valon; | 2024 | unsigned char val, valoff, valon; |
| 1654 | 2025 | ||
| @@ -1659,42 +2030,74 @@ snd_azf3328_test_bit(unsigned int reg, int bit) | |||
| 1659 | 2030 | ||
| 1660 | outb(val|(1 << bit), reg); | 2031 | outb(val|(1 << bit), reg); |
| 1661 | valon = inb(reg); | 2032 | valon = inb(reg); |
| 1662 | 2033 | ||
| 1663 | outb(val, reg); | 2034 | outb(val, reg); |
| 1664 | 2035 | ||
| 1665 | printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", reg, bit, val, valoff, valon); | 2036 | printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", |
| 2037 | reg, bit, val, valoff, valon | ||
| 2038 | ); | ||
| 1666 | } | 2039 | } |
| 1667 | #endif | 2040 | #endif |
| 1668 | 2041 | ||
| 1669 | #if DEBUG_MISC | 2042 | static inline void |
| 1670 | static void | ||
| 1671 | snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) | 2043 | snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) |
| 1672 | { | 2044 | { |
| 2045 | #if DEBUG_MISC | ||
| 1673 | u16 tmp; | 2046 | u16 tmp; |
| 1674 | 2047 | ||
| 1675 | snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq); | 2048 | snd_azf3328_dbgmisc( |
| 1676 | 2049 | "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " | |
| 1677 | snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_inb(chip, 0), snd_azf3328_io2_inb(chip, 1), snd_azf3328_io2_inb(chip, 2), snd_azf3328_io2_inb(chip, 3), snd_azf3328_io2_inb(chip, 4), snd_azf3328_io2_inb(chip, 5)); | 2050 | "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", |
| 1678 | 2051 | chip->codec_io, chip->game_io, chip->mpu_io, | |
| 1679 | for (tmp=0; tmp <= 0x01; tmp += 1) | 2052 | chip->opl3_io, chip->mixer_io, chip->irq |
| 1680 | snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); | 2053 | ); |
| 2054 | |||
| 2055 | snd_azf3328_dbgmisc("game %02x %02x %02x %02x %02x %02x\n", | ||
| 2056 | snd_azf3328_game_inb(chip, 0), | ||
| 2057 | snd_azf3328_game_inb(chip, 1), | ||
| 2058 | snd_azf3328_game_inb(chip, 2), | ||
| 2059 | snd_azf3328_game_inb(chip, 3), | ||
| 2060 | snd_azf3328_game_inb(chip, 4), | ||
| 2061 | snd_azf3328_game_inb(chip, 5) | ||
| 2062 | ); | ||
| 2063 | |||
| 2064 | for (tmp = 0; tmp < 0x07; tmp += 1) | ||
| 2065 | snd_azf3328_dbgmisc("mpu_io 0x%04x\n", inb(chip->mpu_io + tmp)); | ||
| 2066 | |||
| 2067 | for (tmp = 0; tmp <= 0x07; tmp += 1) | ||
| 2068 | snd_azf3328_dbgmisc("0x%02x: game200 0x%04x, game208 0x%04x\n", | ||
| 2069 | tmp, inb(0x200 + tmp), inb(0x208 + tmp)); | ||
| 2070 | |||
| 2071 | for (tmp = 0; tmp <= 0x01; tmp += 1) | ||
| 2072 | snd_azf3328_dbgmisc( | ||
| 2073 | "0x%02x: mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, " | ||
| 2074 | "mpu330 0x%04x opl388 0x%04x opl38c 0x%04x\n", | ||
| 2075 | tmp, | ||
| 2076 | inb(0x300 + tmp), | ||
| 2077 | inb(0x310 + tmp), | ||
| 2078 | inb(0x320 + tmp), | ||
| 2079 | inb(0x330 + tmp), | ||
| 2080 | inb(0x388 + tmp), | ||
| 2081 | inb(0x38c + tmp) | ||
| 2082 | ); | ||
| 1681 | 2083 | ||
| 1682 | for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) | 2084 | for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) |
| 1683 | snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", tmp, snd_azf3328_codec_inw(chip, tmp)); | 2085 | snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", |
| 2086 | tmp, snd_azf3328_codec_inw(chip, tmp) | ||
| 2087 | ); | ||
| 1684 | 2088 | ||
| 1685 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) | 2089 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) |
| 1686 | snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", tmp, snd_azf3328_mixer_inw(chip, tmp)); | 2090 | snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", |
| 2091 | tmp, snd_azf3328_mixer_inw(chip, tmp) | ||
| 2092 | ); | ||
| 2093 | #endif /* DEBUG_MISC */ | ||
| 1687 | } | 2094 | } |
| 1688 | #else | ||
| 1689 | static inline void | ||
| 1690 | snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) {} | ||
| 1691 | #endif | ||
| 1692 | 2095 | ||
| 1693 | static int __devinit | 2096 | static int __devinit |
| 1694 | snd_azf3328_create(struct snd_card *card, | 2097 | snd_azf3328_create(struct snd_card *card, |
| 1695 | struct pci_dev *pci, | 2098 | struct pci_dev *pci, |
| 1696 | unsigned long device_type, | 2099 | unsigned long device_type, |
| 1697 | struct snd_azf3328 ** rchip) | 2100 | struct snd_azf3328 **rchip) |
| 1698 | { | 2101 | { |
| 1699 | struct snd_azf3328 *chip; | 2102 | struct snd_azf3328 *chip; |
| 1700 | int err; | 2103 | int err; |
| @@ -1705,7 +2108,8 @@ snd_azf3328_create(struct snd_card *card, | |||
| 1705 | 2108 | ||
| 1706 | *rchip = NULL; | 2109 | *rchip = NULL; |
| 1707 | 2110 | ||
| 1708 | if ((err = pci_enable_device(pci)) < 0) | 2111 | err = pci_enable_device(pci); |
| 2112 | if (err < 0) | ||
| 1709 | return err; | 2113 | return err; |
| 1710 | 2114 | ||
| 1711 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 2115 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
| @@ -1721,20 +2125,25 @@ snd_azf3328_create(struct snd_card *card, | |||
| 1721 | /* check if we can restrict PCI DMA transfers to 24 bits */ | 2125 | /* check if we can restrict PCI DMA transfers to 24 bits */ |
| 1722 | if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 || | 2126 | if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 || |
| 1723 | pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) { | 2127 | pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) { |
| 1724 | snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); | 2128 | snd_printk(KERN_ERR "architecture does not support " |
| 2129 | "24bit PCI busmaster DMA\n" | ||
| 2130 | ); | ||
| 1725 | err = -ENXIO; | 2131 | err = -ENXIO; |
| 1726 | goto out_err; | 2132 | goto out_err; |
| 1727 | } | 2133 | } |
| 1728 | 2134 | ||
| 1729 | if ((err = pci_request_regions(pci, "Aztech AZF3328")) < 0) { | 2135 | err = pci_request_regions(pci, "Aztech AZF3328"); |
| 2136 | if (err < 0) | ||
| 1730 | goto out_err; | 2137 | goto out_err; |
| 1731 | } | ||
| 1732 | 2138 | ||
| 1733 | chip->codec_port = pci_resource_start(pci, 0); | 2139 | chip->codec_io = pci_resource_start(pci, 0); |
| 1734 | chip->io2_port = pci_resource_start(pci, 1); | 2140 | chip->game_io = pci_resource_start(pci, 1); |
| 1735 | chip->mpu_port = pci_resource_start(pci, 2); | 2141 | chip->mpu_io = pci_resource_start(pci, 2); |
| 1736 | chip->synth_port = pci_resource_start(pci, 3); | 2142 | chip->opl3_io = pci_resource_start(pci, 3); |
| 1737 | chip->mixer_port = pci_resource_start(pci, 4); | 2143 | chip->mixer_io = pci_resource_start(pci, 4); |
| 2144 | |||
| 2145 | chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00; | ||
| 2146 | chip->audio_stream[AZF_CAPTURE].portbase = chip->codec_io + 0x20; | ||
| 1738 | 2147 | ||
| 1739 | if (request_irq(pci->irq, snd_azf3328_interrupt, | 2148 | if (request_irq(pci->irq, snd_azf3328_interrupt, |
| 1740 | IRQF_SHARED, card->shortname, chip)) { | 2149 | IRQF_SHARED, card->shortname, chip)) { |
| @@ -1747,29 +2156,29 @@ snd_azf3328_create(struct snd_card *card, | |||
| 1747 | synchronize_irq(chip->irq); | 2156 | synchronize_irq(chip->irq); |
| 1748 | 2157 | ||
| 1749 | snd_azf3328_debug_show_ports(chip); | 2158 | snd_azf3328_debug_show_ports(chip); |
| 1750 | 2159 | ||
| 1751 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | 2160 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); |
| 2161 | if (err < 0) | ||
| 1752 | goto out_err; | 2162 | goto out_err; |
| 1753 | } | ||
| 1754 | 2163 | ||
| 1755 | /* create mixer interface & switches */ | 2164 | /* create mixer interface & switches */ |
| 1756 | if ((err = snd_azf3328_mixer_new(chip)) < 0) | 2165 | err = snd_azf3328_mixer_new(chip); |
| 2166 | if (err < 0) | ||
| 1757 | goto out_err; | 2167 | goto out_err; |
| 1758 | 2168 | ||
| 1759 | #if 0 | 2169 | /* shutdown codecs to save power */ |
| 1760 | /* set very low bitrate to reduce noise and power consumption? */ | 2170 | /* have snd_azf3328_codec_activity() act properly */ |
| 1761 | snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, 5512, 8, 1); | 2171 | chip->audio_stream[AZF_PLAYBACK].running = 1; |
| 1762 | #endif | 2172 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); |
| 1763 | 2173 | ||
| 1764 | /* standard chip init stuff */ | 2174 | /* standard chip init stuff */ |
| 1765 | /* default IRQ init value */ | 2175 | /* default IRQ init value */ |
| 1766 | tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; | 2176 | tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; |
| 1767 | 2177 | ||
| 1768 | spin_lock_irq(&chip->reg_lock); | 2178 | spin_lock_irq(&chip->reg_lock); |
| 1769 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); | 2179 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); |
| 1770 | snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); | 2180 | snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); |
| 1771 | snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); | 2181 | snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); |
| 1772 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); /* disable timer */ | ||
| 1773 | spin_unlock_irq(&chip->reg_lock); | 2182 | spin_unlock_irq(&chip->reg_lock); |
| 1774 | 2183 | ||
| 1775 | snd_card_set_dev(card, &pci->dev); | 2184 | snd_card_set_dev(card, &pci->dev); |
| @@ -1805,52 +2214,61 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 1805 | return -ENOENT; | 2214 | return -ENOENT; |
| 1806 | } | 2215 | } |
| 1807 | 2216 | ||
| 1808 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0 ); | 2217 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); |
| 1809 | if (card == NULL) | 2218 | if (card == NULL) |
| 1810 | return -ENOMEM; | 2219 | return -ENOMEM; |
| 1811 | 2220 | ||
| 1812 | strcpy(card->driver, "AZF3328"); | 2221 | strcpy(card->driver, "AZF3328"); |
| 1813 | strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); | 2222 | strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); |
| 1814 | 2223 | ||
| 1815 | if ((err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip)) < 0) { | 2224 | err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip); |
| 2225 | if (err < 0) | ||
| 1816 | goto out_err; | 2226 | goto out_err; |
| 1817 | } | ||
| 1818 | 2227 | ||
| 1819 | card->private_data = chip; | 2228 | card->private_data = chip; |
| 1820 | 2229 | ||
| 1821 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, | 2230 | err = snd_mpu401_uart_new( |
| 1822 | chip->mpu_port, MPU401_INFO_INTEGRATED, | 2231 | card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED, |
| 1823 | pci->irq, 0, &chip->rmidi)) < 0) { | 2232 | pci->irq, 0, &chip->rmidi |
| 1824 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); | 2233 | ); |
| 2234 | if (err < 0) { | ||
| 2235 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", | ||
| 2236 | chip->mpu_io | ||
| 2237 | ); | ||
| 1825 | goto out_err; | 2238 | goto out_err; |
| 1826 | } | 2239 | } |
| 1827 | 2240 | ||
| 1828 | if ((err = snd_azf3328_timer(chip, 0)) < 0) { | 2241 | err = snd_azf3328_timer(chip, 0); |
| 2242 | if (err < 0) | ||
| 1829 | goto out_err; | 2243 | goto out_err; |
| 1830 | } | ||
| 1831 | 2244 | ||
| 1832 | if ((err = snd_azf3328_pcm(chip, 0)) < 0) { | 2245 | err = snd_azf3328_pcm(chip, 0); |
| 2246 | if (err < 0) | ||
| 1833 | goto out_err; | 2247 | goto out_err; |
| 1834 | } | ||
| 1835 | 2248 | ||
| 1836 | if (snd_opl3_create(card, chip->synth_port, chip->synth_port+2, | 2249 | if (snd_opl3_create(card, chip->opl3_io, chip->opl3_io+2, |
| 1837 | OPL3_HW_AUTO, 1, &opl3) < 0) { | 2250 | OPL3_HW_AUTO, 1, &opl3) < 0) { |
| 1838 | snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", | 2251 | snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", |
| 1839 | chip->synth_port, chip->synth_port+2 ); | 2252 | chip->opl3_io, chip->opl3_io+2 |
| 2253 | ); | ||
| 1840 | } else { | 2254 | } else { |
| 1841 | if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { | 2255 | /* need to use IDs 1, 2 since ID 0 is snd_azf3328_timer above */ |
| 2256 | err = snd_opl3_timer_new(opl3, 1, 2); | ||
| 2257 | if (err < 0) | ||
| 2258 | goto out_err; | ||
| 2259 | err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); | ||
| 2260 | if (err < 0) | ||
| 1842 | goto out_err; | 2261 | goto out_err; |
| 1843 | } | ||
| 1844 | } | 2262 | } |
| 1845 | 2263 | ||
| 1846 | opl3->private_data = chip; | 2264 | opl3->private_data = chip; |
| 1847 | 2265 | ||
| 1848 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 2266 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
| 1849 | card->shortname, chip->codec_port, chip->irq); | 2267 | card->shortname, chip->codec_io, chip->irq); |
| 1850 | 2268 | ||
| 1851 | if ((err = snd_card_register(card)) < 0) { | 2269 | err = snd_card_register(card); |
| 2270 | if (err < 0) | ||
| 1852 | goto out_err; | 2271 | goto out_err; |
| 1853 | } | ||
| 1854 | 2272 | ||
| 1855 | #ifdef MODULE | 2273 | #ifdef MODULE |
| 1856 | printk( | 2274 | printk( |
| @@ -1861,19 +2279,18 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 1861 | 1024000 / seqtimer_scaling, seqtimer_scaling); | 2279 | 1024000 / seqtimer_scaling, seqtimer_scaling); |
| 1862 | #endif | 2280 | #endif |
| 1863 | 2281 | ||
| 1864 | if (snd_azf3328_config_joystick(chip, dev) < 0) | 2282 | snd_azf3328_gameport(chip, dev); |
| 1865 | snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, | ||
| 1866 | snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); | ||
| 1867 | 2283 | ||
| 1868 | pci_set_drvdata(pci, card); | 2284 | pci_set_drvdata(pci, card); |
| 1869 | dev++; | 2285 | dev++; |
| 1870 | 2286 | ||
| 1871 | err = 0; | 2287 | err = 0; |
| 1872 | goto out; | 2288 | goto out; |
| 1873 | 2289 | ||
| 1874 | out_err: | 2290 | out_err: |
| 2291 | snd_printk(KERN_ERR "azf3328: something failed, exiting\n"); | ||
| 1875 | snd_card_free(card); | 2292 | snd_card_free(card); |
| 1876 | 2293 | ||
| 1877 | out: | 2294 | out: |
| 1878 | snd_azf3328_dbgcallleave(); | 2295 | snd_azf3328_dbgcallleave(); |
| 1879 | return err; | 2296 | return err; |
| @@ -1894,27 +2311,31 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | |||
| 1894 | { | 2311 | { |
| 1895 | struct snd_card *card = pci_get_drvdata(pci); | 2312 | struct snd_card *card = pci_get_drvdata(pci); |
| 1896 | struct snd_azf3328 *chip = card->private_data; | 2313 | struct snd_azf3328 *chip = card->private_data; |
| 1897 | int reg; | 2314 | unsigned reg; |
| 1898 | 2315 | ||
| 1899 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2316 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
| 1900 | 2317 | ||
| 1901 | snd_pcm_suspend_all(chip->pcm); | 2318 | snd_pcm_suspend_all(chip->pcm); |
| 1902 | 2319 | ||
| 1903 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | 2320 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) |
| 1904 | chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2); | 2321 | chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); |
| 1905 | 2322 | ||
| 1906 | /* make sure to disable master volume etc. to prevent looping sound */ | 2323 | /* make sure to disable master volume etc. to prevent looping sound */ |
| 1907 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | 2324 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); |
| 1908 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 2325 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); |
| 1909 | 2326 | ||
| 1910 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | 2327 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) |
| 1911 | chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2); | 2328 | chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2); |
| 1912 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | 2329 | |
| 1913 | chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2); | 2330 | /* manually store the one currently relevant write-only reg, too */ |
| 1914 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | 2331 | chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH; |
| 1915 | chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2); | 2332 | |
| 1916 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | 2333 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) |
| 1917 | chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2); | 2334 | chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); |
| 2335 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | ||
| 2336 | chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2); | ||
| 2337 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | ||
| 2338 | chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2); | ||
| 1918 | 2339 | ||
| 1919 | pci_disable_device(pci); | 2340 | pci_disable_device(pci); |
| 1920 | pci_save_state(pci); | 2341 | pci_save_state(pci); |
| @@ -1927,7 +2348,7 @@ snd_azf3328_resume(struct pci_dev *pci) | |||
| 1927 | { | 2348 | { |
| 1928 | struct snd_card *card = pci_get_drvdata(pci); | 2349 | struct snd_card *card = pci_get_drvdata(pci); |
| 1929 | struct snd_azf3328 *chip = card->private_data; | 2350 | struct snd_azf3328 *chip = card->private_data; |
| 1930 | int reg; | 2351 | unsigned reg; |
| 1931 | 2352 | ||
| 1932 | pci_set_power_state(pci, PCI_D0); | 2353 | pci_set_power_state(pci, PCI_D0); |
| 1933 | pci_restore_state(pci); | 2354 | pci_restore_state(pci); |
| @@ -1939,23 +2360,21 @@ snd_azf3328_resume(struct pci_dev *pci) | |||
| 1939 | } | 2360 | } |
| 1940 | pci_set_master(pci); | 2361 | pci_set_master(pci); |
| 1941 | 2362 | ||
| 1942 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | 2363 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) |
| 1943 | outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2); | 2364 | outw(chip->saved_regs_game[reg], chip->game_io + reg * 2); |
| 1944 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | 2365 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) |
| 1945 | outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2); | 2366 | outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2); |
| 1946 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | 2367 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) |
| 1947 | outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2); | 2368 | outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); |
| 1948 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | 2369 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) |
| 1949 | outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2); | 2370 | outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); |
| 1950 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | 2371 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) |
| 1951 | outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2); | 2372 | outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2); |
| 1952 | 2373 | ||
| 1953 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2374 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
| 1954 | return 0; | 2375 | return 0; |
| 1955 | } | 2376 | } |
| 1956 | #endif | 2377 | #endif /* CONFIG_PM */ |
| 1957 | |||
| 1958 | |||
| 1959 | 2378 | ||
| 1960 | 2379 | ||
| 1961 | static struct pci_driver driver = { | 2380 | static struct pci_driver driver = { |
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index 679fa992e2bc..7e3e8942d073 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | #ifndef __SOUND_AZT3328_H | 1 | #ifndef __SOUND_AZT3328_H |
| 2 | #define __SOUND_AZT3328_H | 2 | #define __SOUND_AZT3328_H |
| 3 | 3 | ||
| 4 | /* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 */ | 4 | /* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 |
| 5 | * "WRITE_ONLY" == register does not indicate actual bit values */ | ||
| 5 | 6 | ||
| 6 | /*** main I/O area port indices ***/ | 7 | /*** main I/O area port indices ***/ |
| 7 | /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ | 8 | /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ |
| @@ -54,7 +55,10 @@ | |||
| 54 | #define SOUNDFORMAT_XTAL1 0x00 | 55 | #define SOUNDFORMAT_XTAL1 0x00 |
| 55 | #define SOUNDFORMAT_XTAL2 0x01 | 56 | #define SOUNDFORMAT_XTAL2 0x01 |
| 56 | /* all _SUSPECTED_ values are not used by Windows drivers, so we don't | 57 | /* all _SUSPECTED_ values are not used by Windows drivers, so we don't |
| 57 | * have any hard facts, only rough measurements */ | 58 | * have any hard facts, only rough measurements. |
| 59 | * All we know is that the crystal used on the board has 24.576MHz, | ||
| 60 | * like many soundcards (which results in the frequencies below when | ||
| 61 | * using certain divider values selected by the values below) */ | ||
| 58 | #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 | 62 | #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 |
| 59 | #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 | 63 | #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 |
| 60 | #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 | 64 | #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 |
| @@ -72,6 +76,26 @@ | |||
| 72 | #define SOUNDFORMAT_FLAG_16BIT 0x0010 | 76 | #define SOUNDFORMAT_FLAG_16BIT 0x0010 |
| 73 | #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 | 77 | #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 |
| 74 | 78 | ||
| 79 | /* define frequency helpers, for maximum value safety */ | ||
| 80 | enum azf_freq_t { | ||
| 81 | #define AZF_FREQ(rate) AZF_FREQ_##rate = rate | ||
| 82 | AZF_FREQ(4000), | ||
| 83 | AZF_FREQ(4800), | ||
| 84 | AZF_FREQ(5512), | ||
| 85 | AZF_FREQ(6620), | ||
| 86 | AZF_FREQ(8000), | ||
| 87 | AZF_FREQ(9600), | ||
| 88 | AZF_FREQ(11025), | ||
| 89 | AZF_FREQ(13240), | ||
| 90 | AZF_FREQ(16000), | ||
| 91 | AZF_FREQ(22050), | ||
| 92 | AZF_FREQ(32000), | ||
| 93 | AZF_FREQ(44100), | ||
| 94 | AZF_FREQ(48000), | ||
| 95 | AZF_FREQ(66200), | ||
| 96 | #undef AZF_FREQ | ||
| 97 | } AZF_FREQUENCIES; | ||
| 98 | |||
| 75 | /** recording area (see also: playback bit flag definitions) **/ | 99 | /** recording area (see also: playback bit flag definitions) **/ |
| 76 | #define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ | 100 | #define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ |
| 77 | #define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ | 101 | #define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ |
| @@ -97,40 +121,171 @@ | |||
| 97 | 121 | ||
| 98 | /** DirectX timer, main interrupt area (FIXME: and something else?) **/ | 122 | /** DirectX timer, main interrupt area (FIXME: and something else?) **/ |
| 99 | #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ | 123 | #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ |
| 100 | #define TIMER_VALUE_MASK 0x000fffffUL /* timer countdown value; triggers IRQ when timer is finished */ | 124 | /* timer countdown value; triggers IRQ when timer is finished */ |
| 101 | #define TIMER_ENABLE_COUNTDOWN 0x01000000UL /* activate the timer countdown */ | 125 | #define TIMER_VALUE_MASK 0x000fffffUL |
| 102 | #define TIMER_ENABLE_IRQ 0x02000000UL /* trigger timer IRQ on zero transition */ | 126 | /* activate timer countdown */ |
| 103 | #define TIMER_ACK_IRQ 0x04000000UL /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) had 0x0020 set upon IRQ handler */ | 127 | #define TIMER_COUNTDOWN_ENABLE 0x01000000UL |
| 128 | /* trigger timer IRQ on zero transition */ | ||
| 129 | #define TIMER_IRQ_ENABLE 0x02000000UL | ||
| 130 | /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) | ||
| 131 | * had 0x0020 set upon IRQ handler */ | ||
| 132 | #define TIMER_IRQ_ACK 0x04000000UL | ||
| 104 | #define IDX_IO_IRQSTATUS 0x64 | 133 | #define IDX_IO_IRQSTATUS 0x64 |
| 105 | #define IRQ_PLAYBACK 0x0001 | 134 | /* some IRQ bit in here might also be used to signal a power-management timer |
| 106 | #define IRQ_RECORDING 0x0002 | 135 | * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing). |
| 107 | #define IRQ_MPU401 0x0010 | 136 | * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which |
| 108 | #define IRQ_TIMER 0x0020 /* DirectX timer */ | 137 | * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */ |
| 109 | #define IRQ_UNKNOWN1 0x0040 /* probably unused, or possibly I2S port? or gameport IRQ? */ | 138 | |
| 110 | #define IRQ_UNKNOWN2 0x0080 /* probably unused, or possibly I2S port? or gameport IRQ? */ | 139 | #define IRQ_PLAYBACK 0x0001 |
| 140 | #define IRQ_RECORDING 0x0002 | ||
| 141 | #define IRQ_UNKNOWN1 0x0004 /* most probably I2S port */ | ||
| 142 | #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ | ||
| 143 | #define IRQ_MPU401 0x0010 | ||
| 144 | #define IRQ_TIMER 0x0020 /* DirectX timer */ | ||
| 145 | #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */ | ||
| 146 | #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */ | ||
| 111 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ | 147 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ |
| 112 | #define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ | 148 | /* this is set to e.g. 0x3ff or 0x300, and writable; |
| 113 | #define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */ | 149 | * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ |
| 114 | #define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */ | 150 | #define IDX_IO_SOME_VALUE 0x68 |
| 115 | #define IDX_IO_6CH 0x6C | 151 | #define IO_68_RANDOM_TOGGLE1 0x0100 /* toggles randomly */ |
| 116 | #define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ | 152 | #define IO_68_RANDOM_TOGGLE2 0x0200 /* toggles randomly */ |
| 117 | /* further I/O indices not saved/restored, so probably not used */ | 153 | /* umm, nope, behaviour of these bits changes depending on what we wrote |
| 154 | * to 0x6b!! | ||
| 155 | * And they change upon playback/stop, too: | ||
| 156 | * Writing a value to 0x68 will display this exact value during playback, | ||
| 157 | * too but when stopped it can fall back to a rather different | ||
| 158 | * seemingly random value). Hmm, possibly this is a register which | ||
| 159 | * has a remote shadow which needs proper device supply which only exists | ||
| 160 | * in case playback is active? Or is this driver-induced? | ||
| 161 | */ | ||
| 162 | |||
| 163 | /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); | ||
| 164 | * actually inhibits PCM playback!!! maybe power management??: */ | ||
| 165 | #define IDX_IO_6AH 0x6A /* WRITE_ONLY! */ | ||
| 166 | /* bit 5: enabling this will activate permanent counting of bytes 2/3 | ||
| 167 | * at gameport I/O (0xb402/3) (equal values each) and cause | ||
| 168 | * gameport legacy I/O at 0x0200 to be _DISABLED_! | ||
| 169 | * Is this Digital Enhanced Game Port Enable??? Or maybe it's Testmode | ||
| 170 | * for Enhanced Digital Gameport (see 4D Wave DX card): */ | ||
| 171 | #define IO_6A_SOMETHING1_GAMEPORT 0x0020 | ||
| 172 | /* bit 8; sure, this _pauses_ playback (later resumes at same spot!), | ||
| 173 | * but what the heck is this really about??: */ | ||
| 174 | #define IO_6A_PAUSE_PLAYBACK_BIT8 0x0100 | ||
| 175 | /* bit 9; sure, this _pauses_ playback (later resumes at same spot!), | ||
| 176 | * but what the heck is this really about??: */ | ||
| 177 | #define IO_6A_PAUSE_PLAYBACK_BIT9 0x0200 | ||
| 178 | /* BIT8 and BIT9 are _NOT_ able to affect OPL3 MIDI playback, | ||
| 179 | * thus it suggests influence on PCM only!! | ||
| 180 | * However OTOH there seems to be no bit anywhere around here | ||
| 181 | * which is able to disable OPL3... */ | ||
| 182 | /* bit 10: enabling this actually changes values at legacy gameport | ||
| 183 | * I/O address (0x200); is this enabling of the Digital Enhanced Game Port??? | ||
| 184 | * Or maybe this simply switches off the NE558 circuit, since enabling this | ||
| 185 | * still lets us evaluate button states, but not axis states */ | ||
| 186 | #define IO_6A_SOMETHING2_GAMEPORT 0x0400 | ||
| 187 | /* writing 0x0300: causes quite some crackling during | ||
| 188 | * PC activity such as switching windows (PCI traffic?? | ||
| 189 | * --> FIFO/timing settings???) */ | ||
| 190 | /* writing 0x0100 plus/or 0x0200 inhibits playback */ | ||
| 191 | /* since the Windows .INF file has Flag_Enable_JoyStick and | ||
| 192 | * Flag_Enable_SB_DOS_Emulation directly together, it stands to reason | ||
| 193 | * that some other bit in this same register might be responsible | ||
| 194 | * for SB DOS Emulation activation (note that the file did NOT define | ||
| 195 | * a switch for OPL3!) */ | ||
| 196 | #define IDX_IO_6CH 0x6C /* unknown; fully read-writable */ | ||
| 197 | #define IDX_IO_6EH 0x6E | ||
| 198 | /* writing 0xffff returns 0x83fe (or 0x03fe only). | ||
| 199 | * writing 0x83 (and only 0x83!!) to 0x6f will cause 0x6c to switch | ||
| 200 | * from 0000 to ffff. */ | ||
| 118 | 201 | ||
| 202 | /* further I/O indices not saved/restored and not readable after writing, | ||
| 203 | * so probably not used */ | ||
| 119 | 204 | ||
| 120 | /*** I/O 2 area port indices ***/ | 205 | |
| 206 | /*** Gameport area port indices ***/ | ||
| 121 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ | 207 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ |
| 122 | #define AZF_IO_SIZE_IO2 0x08 | 208 | #define AZF_IO_SIZE_GAME 0x08 |
| 123 | #define AZF_IO_SIZE_IO2_PM 0x06 | 209 | #define AZF_IO_SIZE_GAME_PM 0x06 |
| 210 | |||
| 211 | enum { | ||
| 212 | AZF_GAME_LEGACY_IO_PORT = 0x200 | ||
| 213 | } AZF_GAME_CONFIGS; | ||
| 214 | |||
| 215 | #define IDX_GAME_LEGACY_COMPATIBLE 0x00 | ||
| 216 | /* in some operation mode, writing anything to this port | ||
| 217 | * triggers an interrupt: | ||
| 218 | * yup, that's in case IDX_GAME_01H has one of the | ||
| 219 | * axis measurement bits enabled | ||
| 220 | * (and of course one needs to have GAME_HWCFG_IRQ_ENABLE, too) */ | ||
| 221 | |||
| 222 | #define IDX_GAME_AXES_CONFIG 0x01 | ||
| 223 | /* NOTE: layout of this register awfully similar (read: "identical??") | ||
| 224 | * to AD1815JS.pdf (p.29) */ | ||
| 225 | |||
| 226 | /* enables axis 1 (X axis) measurement: */ | ||
| 227 | #define GAME_AXES_ENABLE_1 0x01 | ||
| 228 | /* enables axis 2 (Y axis) measurement: */ | ||
| 229 | #define GAME_AXES_ENABLE_2 0x02 | ||
| 230 | /* enables axis 3 (X axis) measurement: */ | ||
| 231 | #define GAME_AXES_ENABLE_3 0x04 | ||
| 232 | /* enables axis 4 (Y axis) measurement: */ | ||
| 233 | #define GAME_AXES_ENABLE_4 0x08 | ||
| 234 | /* selects the current axis to read the measured value of | ||
| 235 | * (at IDX_GAME_AXIS_VALUE): | ||
| 236 | * 00 = axis 1, 01 = axis 2, 10 = axis 3, 11 = axis 4: */ | ||
| 237 | #define GAME_AXES_READ_MASK 0x30 | ||
| 238 | /* enable to have the latch continuously accept ADC values | ||
| 239 | * (and continuously cause interrupts in case interrupts are enabled); | ||
| 240 | * AD1815JS.pdf says it's ~16ms interval there: */ | ||
| 241 | #define GAME_AXES_LATCH_ENABLE 0x40 | ||
| 242 | /* joystick data (measured axes) ready for reading: */ | ||
| 243 | #define GAME_AXES_SAMPLING_READY 0x80 | ||
| 244 | |||
| 245 | /* NOTE: other card specs (SiS960 and others!) state that the | ||
| 246 | * game position latches should be frozen when reading and be freed | ||
| 247 | * (== reset?) after reading!!! | ||
| 248 | * Freezing most likely means disabling 0x40 (GAME_AXES_LATCH_ENABLE), | ||
| 249 | * but how to free the value? */ | ||
| 250 | /* An internet search for "gameport latch ADC" should provide some insight | ||
| 251 | * into how to program such a gameport system. */ | ||
| 252 | |||
| 253 | /* writing 0xf0 to 01H once reset both counters to 0, in some special mode!? | ||
| 254 | * yup, in case 6AH 0x20 is not enabled | ||
| 255 | * (and 0x40 is sufficient, 0xf0 is not needed) */ | ||
| 256 | |||
| 257 | #define IDX_GAME_AXIS_VALUE 0x02 | ||
| 258 | /* R: value of currently configured axis (word value!); | ||
| 259 | * W: trigger axis measurement */ | ||
| 260 | |||
| 261 | #define IDX_GAME_HWCONFIG 0x04 | ||
| 262 | /* note: bits 4 to 7 are never set (== 0) when reading! | ||
| 263 | * --> reserved bits? */ | ||
| 264 | /* enables IRQ notification upon axes measurement ready: */ | ||
| 265 | #define GAME_HWCFG_IRQ_ENABLE 0x01 | ||
| 266 | /* these bits choose a different frequency for the | ||
| 267 | * internal ADC counter increment. | ||
| 268 | * hmm, seems to be a combo of bits: | ||
| 269 | * 00 --> standard frequency | ||
| 270 | * 10 --> 1/2 | ||
| 271 | * 01 --> 1/20 | ||
| 272 | * 11 --> 1/200: */ | ||
| 273 | #define GAME_HWCFG_ADC_COUNTER_FREQ_MASK 0x06 | ||
| 124 | 274 | ||
| 125 | #define IDX_IO2_LEGACY_ADDR 0x04 | 275 | /* enable gameport legacy I/O address (0x200) |
| 126 | #define LEGACY_SOMETHING 0x01 /* OPL3?? */ | 276 | * I was unable to locate any configurability for a different address: */ |
| 127 | #define LEGACY_JOY 0x08 | 277 | #define GAME_HWCFG_LEGACY_ADDRESS_ENABLE 0x08 |
| 128 | 278 | ||
| 279 | /*** MPU401 ***/ | ||
| 129 | #define AZF_IO_SIZE_MPU 0x04 | 280 | #define AZF_IO_SIZE_MPU 0x04 |
| 130 | #define AZF_IO_SIZE_MPU_PM 0x04 | 281 | #define AZF_IO_SIZE_MPU_PM 0x04 |
| 131 | 282 | ||
| 132 | #define AZF_IO_SIZE_SYNTH 0x08 | 283 | /*** OPL3 synth ***/ |
| 133 | #define AZF_IO_SIZE_SYNTH_PM 0x06 | 284 | #define AZF_IO_SIZE_OPL3 0x08 |
| 285 | #define AZF_IO_SIZE_OPL3_PM 0x06 | ||
| 286 | /* hmm, given that a standard OPL3 has 4 registers only, | ||
| 287 | * there might be some enhanced functionality lurking at the end | ||
| 288 | * (especially since register 0x04 has a "non-empty" value 0xfe) */ | ||
| 134 | 289 | ||
| 135 | /*** mixer I/O area port indices ***/ | 290 | /*** mixer I/O area port indices ***/ |
| 136 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) | 291 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index ecbe79b67e43..2f8b28add276 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
| @@ -249,6 +249,11 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
| 249 | .name = "MSI K8N Diamond MB [SB0438]", | 249 | .name = "MSI K8N Diamond MB [SB0438]", |
| 250 | .gpio_type = 2, | 250 | .gpio_type = 2, |
| 251 | .i2c_adc = 1 } , | 251 | .i2c_adc = 1 } , |
| 252 | /* Another MSI K8N Diamond MB, which has apprently a different SSID */ | ||
| 253 | { .serial = 0x10091102, | ||
| 254 | .name = "MSI K8N Diamond MB", | ||
| 255 | .gpio_type = 2, | ||
| 256 | .i2c_adc = 1 } , | ||
| 252 | /* Shuttle XPC SD31P which has an onboard Creative Labs | 257 | /* Shuttle XPC SD31P which has an onboard Creative Labs |
| 253 | * Sound Blaster Live! 24-bit EAX | 258 | * Sound Blaster Live! 24-bit EAX |
| 254 | * high-definition 7.1 audio processor". | 259 | * high-definition 7.1 audio processor". |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 548c9cc81af5..2f283ea6ad9a 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
| @@ -1528,6 +1528,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
| 1528 | .ca0151_chip = 1, | 1528 | .ca0151_chip = 1, |
| 1529 | .spk71 = 1, | 1529 | .spk71 = 1, |
| 1530 | .spdif_bug = 1, | 1530 | .spdif_bug = 1, |
| 1531 | .invert_shared_spdif = 1, /* digital/analog switch swapped */ | ||
| 1531 | .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ | 1532 | .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ |
| 1532 | .ac97_chip = 1} , | 1533 | .ac97_chip = 1} , |
| 1533 | {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, | 1534 | {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index fd221209abcb..f34bbfb705f5 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
| @@ -1578,6 +1578,10 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, | |||
| 1578 | ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; | 1578 | ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; |
| 1579 | else | 1579 | else |
| 1580 | ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; | 1580 | ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; |
| 1581 | if (emu->card_capabilities->invert_shared_spdif) | ||
| 1582 | ucontrol->value.integer.value[0] = | ||
| 1583 | !ucontrol->value.integer.value[0]; | ||
| 1584 | |||
| 1581 | return 0; | 1585 | return 0; |
| 1582 | } | 1586 | } |
| 1583 | 1587 | ||
| @@ -1586,15 +1590,18 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
| 1586 | { | 1590 | { |
| 1587 | unsigned long flags; | 1591 | unsigned long flags; |
| 1588 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 1592 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
| 1589 | unsigned int reg, val; | 1593 | unsigned int reg, val, sw; |
| 1590 | int change = 0; | 1594 | int change = 0; |
| 1591 | 1595 | ||
| 1596 | sw = ucontrol->value.integer.value[0]; | ||
| 1597 | if (emu->card_capabilities->invert_shared_spdif) | ||
| 1598 | sw = !sw; | ||
| 1592 | spin_lock_irqsave(&emu->reg_lock, flags); | 1599 | spin_lock_irqsave(&emu->reg_lock, flags); |
| 1593 | if ( emu->card_capabilities->i2c_adc) { | 1600 | if ( emu->card_capabilities->i2c_adc) { |
| 1594 | /* Do nothing for Audigy 2 ZS Notebook */ | 1601 | /* Do nothing for Audigy 2 ZS Notebook */ |
| 1595 | } else if (emu->audigy) { | 1602 | } else if (emu->audigy) { |
| 1596 | reg = inl(emu->port + A_IOCFG); | 1603 | reg = inl(emu->port + A_IOCFG); |
| 1597 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; | 1604 | val = sw ? A_IOCFG_GPOUT0 : 0; |
| 1598 | change = (reg & A_IOCFG_GPOUT0) != val; | 1605 | change = (reg & A_IOCFG_GPOUT0) != val; |
| 1599 | if (change) { | 1606 | if (change) { |
| 1600 | reg &= ~A_IOCFG_GPOUT0; | 1607 | reg &= ~A_IOCFG_GPOUT0; |
| @@ -1603,7 +1610,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
| 1603 | } | 1610 | } |
| 1604 | } | 1611 | } |
| 1605 | reg = inl(emu->port + HCFG); | 1612 | reg = inl(emu->port + HCFG); |
| 1606 | val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; | 1613 | val = sw ? HCFG_GPOUT0 : 0; |
| 1607 | change |= (reg & HCFG_GPOUT0) != val; | 1614 | change |= (reg & HCFG_GPOUT0) != val; |
| 1608 | if (change) { | 1615 | if (change) { |
| 1609 | reg &= ~HCFG_GPOUT0; | 1616 | reg &= ~HCFG_GPOUT0; |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 916c1dbcd53c..7d379f5131fb 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
| @@ -437,43 +437,49 @@ static void get_single_page_range(struct snd_util_memhdr *hdr, | |||
| 437 | *last_page_ret = last_page; | 437 | *last_page_ret = last_page; |
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | /* release allocated pages */ | ||
| 441 | static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page, | ||
| 442 | int last_page) | ||
| 443 | { | ||
| 444 | int page; | ||
| 445 | |||
| 446 | for (page = first_page; page <= last_page; page++) { | ||
| 447 | free_page((unsigned long)emu->page_ptr_table[page]); | ||
| 448 | emu->page_addr_table[page] = 0; | ||
| 449 | emu->page_ptr_table[page] = NULL; | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 440 | /* | 453 | /* |
| 441 | * allocate kernel pages | 454 | * allocate kernel pages |
| 442 | */ | 455 | */ |
| 443 | static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) | 456 | static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) |
| 444 | { | 457 | { |
| 445 | int page, first_page, last_page; | 458 | int page, first_page, last_page; |
| 446 | struct snd_dma_buffer dmab; | ||
| 447 | 459 | ||
| 448 | emu10k1_memblk_init(blk); | 460 | emu10k1_memblk_init(blk); |
| 449 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); | 461 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); |
| 450 | /* allocate kernel pages */ | 462 | /* allocate kernel pages */ |
| 451 | for (page = first_page; page <= last_page; page++) { | 463 | for (page = first_page; page <= last_page; page++) { |
| 452 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), | 464 | /* first try to allocate from <4GB zone */ |
| 453 | PAGE_SIZE, &dmab) < 0) | 465 | struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 | |
| 454 | goto __fail; | 466 | __GFP_NOWARN); |
| 455 | if (! is_valid_page(emu, dmab.addr)) { | 467 | if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) { |
| 456 | snd_dma_free_pages(&dmab); | 468 | if (p) |
| 457 | goto __fail; | 469 | __free_page(p); |
| 470 | /* try to allocate from <16MB zone */ | ||
| 471 | p = alloc_page(GFP_ATOMIC | GFP_DMA | | ||
| 472 | __GFP_NORETRY | /* no OOM-killer */ | ||
| 473 | __GFP_NOWARN); | ||
| 474 | } | ||
| 475 | if (!p) { | ||
| 476 | __synth_free_pages(emu, first_page, page - 1); | ||
| 477 | return -ENOMEM; | ||
| 458 | } | 478 | } |
| 459 | emu->page_addr_table[page] = dmab.addr; | 479 | emu->page_addr_table[page] = page_to_phys(p); |
| 460 | emu->page_ptr_table[page] = dmab.area; | 480 | emu->page_ptr_table[page] = page_address(p); |
| 461 | } | 481 | } |
| 462 | return 0; | 482 | return 0; |
| 463 | |||
| 464 | __fail: | ||
| 465 | /* release allocated pages */ | ||
| 466 | last_page = page - 1; | ||
| 467 | for (page = first_page; page <= last_page; page++) { | ||
| 468 | dmab.area = emu->page_ptr_table[page]; | ||
| 469 | dmab.addr = emu->page_addr_table[page]; | ||
| 470 | dmab.bytes = PAGE_SIZE; | ||
| 471 | snd_dma_free_pages(&dmab); | ||
| 472 | emu->page_addr_table[page] = 0; | ||
| 473 | emu->page_ptr_table[page] = NULL; | ||
| 474 | } | ||
| 475 | |||
| 476 | return -ENOMEM; | ||
| 477 | } | 483 | } |
| 478 | 484 | ||
| 479 | /* | 485 | /* |
| @@ -481,23 +487,10 @@ __fail: | |||
| 481 | */ | 487 | */ |
| 482 | static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) | 488 | static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) |
| 483 | { | 489 | { |
| 484 | int page, first_page, last_page; | 490 | int first_page, last_page; |
| 485 | struct snd_dma_buffer dmab; | ||
| 486 | 491 | ||
| 487 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); | 492 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); |
| 488 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | 493 | __synth_free_pages(emu, first_page, last_page); |
| 489 | dmab.dev.dev = snd_dma_pci_data(emu->pci); | ||
| 490 | for (page = first_page; page <= last_page; page++) { | ||
| 491 | if (emu->page_ptr_table[page] == NULL) | ||
| 492 | continue; | ||
| 493 | dmab.area = emu->page_ptr_table[page]; | ||
| 494 | dmab.addr = emu->page_addr_table[page]; | ||
| 495 | dmab.bytes = PAGE_SIZE; | ||
| 496 | snd_dma_free_pages(&dmab); | ||
| 497 | emu->page_addr_table[page] = 0; | ||
| 498 | emu->page_ptr_table[page] = NULL; | ||
| 499 | } | ||
| 500 | |||
| 501 | return 0; | 494 | return 0; |
| 502 | } | 495 | } |
| 503 | 496 | ||
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a6be6e3e8716..d2e1093f8e97 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
| @@ -2335,7 +2335,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, | |||
| 2335 | if (!tbl) | 2335 | if (!tbl) |
| 2336 | return -1; | 2336 | return -1; |
| 2337 | if (tbl->value >= 0 && tbl->value < num_configs) { | 2337 | if (tbl->value >= 0 && tbl->value < num_configs) { |
| 2338 | #ifdef CONFIG_SND_DEBUG_DETECT | 2338 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 2339 | char tmp[10]; | 2339 | char tmp[10]; |
| 2340 | const char *model = NULL; | 2340 | const char *model = NULL; |
| 2341 | if (models) | 2341 | if (models) |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index dcd390b2bbaa..efc682888b31 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
| @@ -78,7 +78,7 @@ enum { | |||
| 78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a | 78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a |
| 79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c | 79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c |
| 80 | #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d | 80 | #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d |
| 81 | #define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e | 81 | #define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ |
| 82 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f | 82 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f |
| 83 | /* f10-f1a: GPIO */ | 83 | /* f10-f1a: GPIO */ |
| 84 | #define AC_VERB_GET_GPIO_DATA 0x0f15 | 84 | #define AC_VERB_GET_GPIO_DATA 0x0f15 |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 2177d9af5334..6e18a422d993 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
| @@ -88,7 +88,7 @@ static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, | |||
| 88 | 88 | ||
| 89 | static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) | 89 | static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) |
| 90 | { | 90 | { |
| 91 | #ifndef CONFIG_SND_DEBUG_DETECT | 91 | #ifndef CONFIG_SND_DEBUG_VERBOSE |
| 92 | if (!capable(CAP_SYS_RAWIO)) | 92 | if (!capable(CAP_SYS_RAWIO)) |
| 93 | return -EACCES; | 93 | return -EACCES; |
| 94 | #endif | 94 | #endif |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b3a618eb42cd..16715a68ba5e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
| @@ -55,6 +55,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | |||
| 55 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 55 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
| 56 | static char *model[SNDRV_CARDS]; | 56 | static char *model[SNDRV_CARDS]; |
| 57 | static int position_fix[SNDRV_CARDS]; | 57 | static int position_fix[SNDRV_CARDS]; |
| 58 | static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | ||
| 58 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | 59 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; |
| 59 | static int single_cmd; | 60 | static int single_cmd; |
| 60 | static int enable_msi; | 61 | static int enable_msi; |
| @@ -69,7 +70,9 @@ module_param_array(model, charp, NULL, 0444); | |||
| 69 | MODULE_PARM_DESC(model, "Use the given board model."); | 70 | MODULE_PARM_DESC(model, "Use the given board model."); |
| 70 | module_param_array(position_fix, int, NULL, 0444); | 71 | module_param_array(position_fix, int, NULL, 0444); |
| 71 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " | 72 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " |
| 72 | "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); | 73 | "(0 = auto, 1 = none, 2 = POSBUF)."); |
| 74 | module_param_array(bdl_pos_adj, int, NULL, 0644); | ||
| 75 | MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); | ||
| 73 | module_param_array(probe_mask, int, NULL, 0444); | 76 | module_param_array(probe_mask, int, NULL, 0444); |
| 74 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 77 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
| 75 | module_param(single_cmd, bool, 0444); | 78 | module_param(single_cmd, bool, 0444); |
| @@ -197,6 +200,10 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
| 197 | #define ATIHDMI_NUM_CAPTURE 0 | 200 | #define ATIHDMI_NUM_CAPTURE 0 |
| 198 | #define ATIHDMI_NUM_PLAYBACK 1 | 201 | #define ATIHDMI_NUM_PLAYBACK 1 |
| 199 | 202 | ||
| 203 | /* TERA has 4 playback and 3 capture */ | ||
| 204 | #define TERA_NUM_CAPTURE 3 | ||
| 205 | #define TERA_NUM_PLAYBACK 4 | ||
| 206 | |||
| 200 | /* this number is statically defined for simplicity */ | 207 | /* this number is statically defined for simplicity */ |
| 201 | #define MAX_AZX_DEV 16 | 208 | #define MAX_AZX_DEV 16 |
| 202 | 209 | ||
| @@ -259,9 +266,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
| 259 | /* position fix mode */ | 266 | /* position fix mode */ |
| 260 | enum { | 267 | enum { |
| 261 | POS_FIX_AUTO, | 268 | POS_FIX_AUTO, |
| 262 | POS_FIX_NONE, | 269 | POS_FIX_LPIB, |
| 263 | POS_FIX_POSBUF, | 270 | POS_FIX_POSBUF, |
| 264 | POS_FIX_FIFO, | ||
| 265 | }; | 271 | }; |
| 266 | 272 | ||
| 267 | /* Defines for ATI HD Audio support in SB450 south bridge */ | 273 | /* Defines for ATI HD Audio support in SB450 south bridge */ |
| @@ -285,6 +291,7 @@ struct azx_dev { | |||
| 285 | u32 *posbuf; /* position buffer pointer */ | 291 | u32 *posbuf; /* position buffer pointer */ |
| 286 | 292 | ||
| 287 | unsigned int bufsize; /* size of the play buffer in bytes */ | 293 | unsigned int bufsize; /* size of the play buffer in bytes */ |
| 294 | unsigned int period_bytes; /* size of the period in bytes */ | ||
| 288 | unsigned int frags; /* number for period in the play buffer */ | 295 | unsigned int frags; /* number for period in the play buffer */ |
| 289 | unsigned int fifo_size; /* FIFO size */ | 296 | unsigned int fifo_size; /* FIFO size */ |
| 290 | 297 | ||
| @@ -301,11 +308,11 @@ struct azx_dev { | |||
| 301 | */ | 308 | */ |
| 302 | unsigned char stream_tag; /* assigned stream */ | 309 | unsigned char stream_tag; /* assigned stream */ |
| 303 | unsigned char index; /* stream index */ | 310 | unsigned char index; /* stream index */ |
| 304 | /* for sanity check of position buffer */ | ||
| 305 | unsigned int period_intr; | ||
| 306 | 311 | ||
| 307 | unsigned int opened :1; | 312 | unsigned int opened :1; |
| 308 | unsigned int running :1; | 313 | unsigned int running :1; |
| 314 | unsigned int irq_pending :1; | ||
| 315 | unsigned int irq_ignore :1; | ||
| 309 | }; | 316 | }; |
| 310 | 317 | ||
| 311 | /* CORB/RIRB */ | 318 | /* CORB/RIRB */ |
| @@ -323,6 +330,7 @@ struct azx_rb { | |||
| 323 | struct azx { | 330 | struct azx { |
| 324 | struct snd_card *card; | 331 | struct snd_card *card; |
| 325 | struct pci_dev *pci; | 332 | struct pci_dev *pci; |
| 333 | int dev_index; | ||
| 326 | 334 | ||
| 327 | /* chip type specific */ | 335 | /* chip type specific */ |
| 328 | int driver_type; | 336 | int driver_type; |
| @@ -366,9 +374,13 @@ struct azx { | |||
| 366 | unsigned int single_cmd :1; | 374 | unsigned int single_cmd :1; |
| 367 | unsigned int polling_mode :1; | 375 | unsigned int polling_mode :1; |
| 368 | unsigned int msi :1; | 376 | unsigned int msi :1; |
| 377 | unsigned int irq_pending_warned :1; | ||
| 369 | 378 | ||
| 370 | /* for debugging */ | 379 | /* for debugging */ |
| 371 | unsigned int last_cmd; /* last issued command (to sync) */ | 380 | unsigned int last_cmd; /* last issued command (to sync) */ |
| 381 | |||
| 382 | /* for pending irqs */ | ||
| 383 | struct work_struct irq_pending_work; | ||
| 372 | }; | 384 | }; |
| 373 | 385 | ||
| 374 | /* driver types */ | 386 | /* driver types */ |
| @@ -381,6 +393,7 @@ enum { | |||
| 381 | AZX_DRIVER_SIS, | 393 | AZX_DRIVER_SIS, |
| 382 | AZX_DRIVER_ULI, | 394 | AZX_DRIVER_ULI, |
| 383 | AZX_DRIVER_NVIDIA, | 395 | AZX_DRIVER_NVIDIA, |
| 396 | AZX_DRIVER_TERA, | ||
| 384 | }; | 397 | }; |
| 385 | 398 | ||
| 386 | static char *driver_short_names[] __devinitdata = { | 399 | static char *driver_short_names[] __devinitdata = { |
| @@ -392,6 +405,7 @@ static char *driver_short_names[] __devinitdata = { | |||
| 392 | [AZX_DRIVER_SIS] = "HDA SIS966", | 405 | [AZX_DRIVER_SIS] = "HDA SIS966", |
| 393 | [AZX_DRIVER_ULI] = "HDA ULI M5461", | 406 | [AZX_DRIVER_ULI] = "HDA ULI M5461", |
| 394 | [AZX_DRIVER_NVIDIA] = "HDA NVidia", | 407 | [AZX_DRIVER_NVIDIA] = "HDA NVidia", |
| 408 | [AZX_DRIVER_TERA] = "HDA Teradici", | ||
| 395 | }; | 409 | }; |
| 396 | 410 | ||
| 397 | /* | 411 | /* |
| @@ -426,11 +440,6 @@ static char *driver_short_names[] __devinitdata = { | |||
| 426 | /* for pcm support */ | 440 | /* for pcm support */ |
| 427 | #define get_azx_dev(substream) (substream->runtime->private_data) | 441 | #define get_azx_dev(substream) (substream->runtime->private_data) |
| 428 | 442 | ||
| 429 | /* Get the upper 32bit of the given dma_addr_t | ||
| 430 | * Compiler should optimize and eliminate the code if dma_addr_t is 32bit | ||
| 431 | */ | ||
| 432 | #define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0) | ||
| 433 | |||
| 434 | static int azx_acquire_irq(struct azx *chip, int do_disconnect); | 443 | static int azx_acquire_irq(struct azx *chip, int do_disconnect); |
| 435 | 444 | ||
| 436 | /* | 445 | /* |
| @@ -461,7 +470,7 @@ static void azx_init_cmd_io(struct azx *chip) | |||
| 461 | chip->corb.addr = chip->rb.addr; | 470 | chip->corb.addr = chip->rb.addr; |
| 462 | chip->corb.buf = (u32 *)chip->rb.area; | 471 | chip->corb.buf = (u32 *)chip->rb.area; |
| 463 | azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); | 472 | azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); |
| 464 | azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr)); | 473 | azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr)); |
| 465 | 474 | ||
| 466 | /* set the corb size to 256 entries (ULI requires explicitly) */ | 475 | /* set the corb size to 256 entries (ULI requires explicitly) */ |
| 467 | azx_writeb(chip, CORBSIZE, 0x02); | 476 | azx_writeb(chip, CORBSIZE, 0x02); |
| @@ -476,7 +485,7 @@ static void azx_init_cmd_io(struct azx *chip) | |||
| 476 | chip->rirb.addr = chip->rb.addr + 2048; | 485 | chip->rirb.addr = chip->rb.addr + 2048; |
| 477 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); | 486 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); |
| 478 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); | 487 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); |
| 479 | azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr)); | 488 | azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); |
| 480 | 489 | ||
| 481 | /* set the rirb size to 256 entries (ULI requires explicitly) */ | 490 | /* set the rirb size to 256 entries (ULI requires explicitly) */ |
| 482 | azx_writeb(chip, RIRBSIZE, 0x02); | 491 | azx_writeb(chip, RIRBSIZE, 0x02); |
| @@ -847,7 +856,7 @@ static void azx_init_chip(struct azx *chip) | |||
| 847 | 856 | ||
| 848 | /* program the position buffer */ | 857 | /* program the position buffer */ |
| 849 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | 858 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); |
| 850 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); | 859 | azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr)); |
| 851 | 860 | ||
| 852 | chip->initialized = 1; | 861 | chip->initialized = 1; |
| 853 | } | 862 | } |
| @@ -908,6 +917,8 @@ static void azx_init_pci(struct azx *chip) | |||
| 908 | } | 917 | } |
| 909 | 918 | ||
| 910 | 919 | ||
| 920 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); | ||
| 921 | |||
| 911 | /* | 922 | /* |
| 912 | * interrupt handler | 923 | * interrupt handler |
| 913 | */ | 924 | */ |
| @@ -930,11 +941,23 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
| 930 | azx_dev = &chip->azx_dev[i]; | 941 | azx_dev = &chip->azx_dev[i]; |
| 931 | if (status & azx_dev->sd_int_sta_mask) { | 942 | if (status & azx_dev->sd_int_sta_mask) { |
| 932 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); | 943 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); |
| 933 | if (azx_dev->substream && azx_dev->running) { | 944 | if (!azx_dev->substream || !azx_dev->running) |
| 934 | azx_dev->period_intr++; | 945 | continue; |
| 946 | /* ignore the first dummy IRQ (due to pos_adj) */ | ||
| 947 | if (azx_dev->irq_ignore) { | ||
| 948 | azx_dev->irq_ignore = 0; | ||
| 949 | continue; | ||
| 950 | } | ||
| 951 | /* check whether this IRQ is really acceptable */ | ||
| 952 | if (azx_position_ok(chip, azx_dev)) { | ||
| 953 | azx_dev->irq_pending = 0; | ||
| 935 | spin_unlock(&chip->reg_lock); | 954 | spin_unlock(&chip->reg_lock); |
| 936 | snd_pcm_period_elapsed(azx_dev->substream); | 955 | snd_pcm_period_elapsed(azx_dev->substream); |
| 937 | spin_lock(&chip->reg_lock); | 956 | spin_lock(&chip->reg_lock); |
| 957 | } else { | ||
| 958 | /* bogus IRQ, process it later */ | ||
| 959 | azx_dev->irq_pending = 1; | ||
| 960 | schedule_work(&chip->irq_pending_work); | ||
| 938 | } | 961 | } |
| 939 | } | 962 | } |
| 940 | } | 963 | } |
| @@ -959,59 +982,107 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
| 959 | 982 | ||
| 960 | 983 | ||
| 961 | /* | 984 | /* |
| 985 | * set up a BDL entry | ||
| 986 | */ | ||
| 987 | static int setup_bdle(struct snd_pcm_substream *substream, | ||
| 988 | struct azx_dev *azx_dev, u32 **bdlp, | ||
| 989 | int ofs, int size, int with_ioc) | ||
| 990 | { | ||
| 991 | struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); | ||
| 992 | u32 *bdl = *bdlp; | ||
| 993 | |||
| 994 | while (size > 0) { | ||
| 995 | dma_addr_t addr; | ||
| 996 | int chunk; | ||
| 997 | |||
| 998 | if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) | ||
| 999 | return -EINVAL; | ||
| 1000 | |||
| 1001 | addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); | ||
| 1002 | /* program the address field of the BDL entry */ | ||
| 1003 | bdl[0] = cpu_to_le32((u32)addr); | ||
| 1004 | bdl[1] = cpu_to_le32(upper_32_bits(addr)); | ||
| 1005 | /* program the size field of the BDL entry */ | ||
| 1006 | chunk = PAGE_SIZE - (ofs % PAGE_SIZE); | ||
| 1007 | if (size < chunk) | ||
| 1008 | chunk = size; | ||
| 1009 | bdl[2] = cpu_to_le32(chunk); | ||
| 1010 | /* program the IOC to enable interrupt | ||
| 1011 | * only when the whole fragment is processed | ||
| 1012 | */ | ||
| 1013 | size -= chunk; | ||
| 1014 | bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); | ||
| 1015 | bdl += 4; | ||
| 1016 | azx_dev->frags++; | ||
| 1017 | ofs += chunk; | ||
| 1018 | } | ||
| 1019 | *bdlp = bdl; | ||
| 1020 | return ofs; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | /* | ||
| 962 | * set up BDL entries | 1024 | * set up BDL entries |
| 963 | */ | 1025 | */ |
| 964 | static int azx_setup_periods(struct snd_pcm_substream *substream, | 1026 | static int azx_setup_periods(struct azx *chip, |
| 1027 | struct snd_pcm_substream *substream, | ||
| 965 | struct azx_dev *azx_dev) | 1028 | struct azx_dev *azx_dev) |
| 966 | { | 1029 | { |
| 967 | struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); | ||
| 968 | u32 *bdl; | 1030 | u32 *bdl; |
| 969 | int i, ofs, periods, period_bytes; | 1031 | int i, ofs, periods, period_bytes; |
| 1032 | int pos_adj; | ||
| 970 | 1033 | ||
| 971 | /* reset BDL address */ | 1034 | /* reset BDL address */ |
| 972 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | 1035 | azx_sd_writel(azx_dev, SD_BDLPL, 0); |
| 973 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | 1036 | azx_sd_writel(azx_dev, SD_BDLPU, 0); |
| 974 | 1037 | ||
| 975 | period_bytes = snd_pcm_lib_period_bytes(substream); | 1038 | period_bytes = snd_pcm_lib_period_bytes(substream); |
| 1039 | azx_dev->period_bytes = period_bytes; | ||
| 976 | periods = azx_dev->bufsize / period_bytes; | 1040 | periods = azx_dev->bufsize / period_bytes; |
| 977 | 1041 | ||
| 978 | /* program the initial BDL entries */ | 1042 | /* program the initial BDL entries */ |
| 979 | bdl = (u32 *)azx_dev->bdl.area; | 1043 | bdl = (u32 *)azx_dev->bdl.area; |
| 980 | ofs = 0; | 1044 | ofs = 0; |
| 981 | azx_dev->frags = 0; | 1045 | azx_dev->frags = 0; |
| 982 | for (i = 0; i < periods; i++) { | 1046 | azx_dev->irq_ignore = 0; |
| 983 | int size, rest; | 1047 | pos_adj = bdl_pos_adj[chip->dev_index]; |
| 984 | if (i >= AZX_MAX_BDL_ENTRIES) { | 1048 | if (pos_adj > 0) { |
| 985 | snd_printk(KERN_ERR "Too many BDL entries: " | 1049 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 986 | "buffer=%d, period=%d\n", | 1050 | pos_adj = (pos_adj * runtime->rate + 47999) / 48000; |
| 987 | azx_dev->bufsize, period_bytes); | 1051 | if (!pos_adj) |
| 988 | /* reset */ | 1052 | pos_adj = 1; |
| 989 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | 1053 | pos_adj = frames_to_bytes(runtime, pos_adj); |
| 990 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | 1054 | if (pos_adj >= period_bytes) { |
| 991 | return -EINVAL; | 1055 | snd_printk(KERN_WARNING "Too big adjustment %d\n", |
| 1056 | bdl_pos_adj[chip->dev_index]); | ||
| 1057 | pos_adj = 0; | ||
| 1058 | } else { | ||
| 1059 | ofs = setup_bdle(substream, azx_dev, | ||
| 1060 | &bdl, ofs, pos_adj, 1); | ||
| 1061 | if (ofs < 0) | ||
| 1062 | goto error; | ||
| 1063 | azx_dev->irq_ignore = 1; | ||
| 992 | } | 1064 | } |
| 993 | rest = period_bytes; | 1065 | } else |
| 994 | do { | 1066 | pos_adj = 0; |
| 995 | dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); | 1067 | for (i = 0; i < periods; i++) { |
| 996 | /* program the address field of the BDL entry */ | 1068 | if (i == periods - 1 && pos_adj) |
| 997 | bdl[0] = cpu_to_le32((u32)addr); | 1069 | ofs = setup_bdle(substream, azx_dev, &bdl, ofs, |
| 998 | bdl[1] = cpu_to_le32(upper_32bit(addr)); | 1070 | period_bytes - pos_adj, 0); |
| 999 | /* program the size field of the BDL entry */ | 1071 | else |
| 1000 | size = PAGE_SIZE - (ofs % PAGE_SIZE); | 1072 | ofs = setup_bdle(substream, azx_dev, &bdl, ofs, |
| 1001 | if (rest < size) | 1073 | period_bytes, 1); |
| 1002 | size = rest; | 1074 | if (ofs < 0) |
| 1003 | bdl[2] = cpu_to_le32(size); | 1075 | goto error; |
| 1004 | /* program the IOC to enable interrupt | ||
| 1005 | * only when the whole fragment is processed | ||
| 1006 | */ | ||
| 1007 | rest -= size; | ||
| 1008 | bdl[3] = rest ? 0 : cpu_to_le32(0x01); | ||
| 1009 | bdl += 4; | ||
| 1010 | azx_dev->frags++; | ||
| 1011 | ofs += size; | ||
| 1012 | } while (rest > 0); | ||
| 1013 | } | 1076 | } |
| 1014 | return 0; | 1077 | return 0; |
| 1078 | |||
| 1079 | error: | ||
| 1080 | snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", | ||
| 1081 | azx_dev->bufsize, period_bytes); | ||
| 1082 | /* reset */ | ||
| 1083 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||
| 1084 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||
| 1085 | return -EINVAL; | ||
| 1015 | } | 1086 | } |
| 1016 | 1087 | ||
| 1017 | /* | 1088 | /* |
| @@ -1062,7 +1133,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
| 1062 | /* lower BDL address */ | 1133 | /* lower BDL address */ |
| 1063 | azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); | 1134 | azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); |
| 1064 | /* upper BDL address */ | 1135 | /* upper BDL address */ |
| 1065 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr)); | 1136 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); |
| 1066 | 1137 | ||
| 1067 | /* enable the position buffer */ | 1138 | /* enable the position buffer */ |
| 1068 | if (chip->position_fix == POS_FIX_POSBUF || | 1139 | if (chip->position_fix == POS_FIX_POSBUF || |
| @@ -1085,7 +1156,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
| 1085 | */ | 1156 | */ |
| 1086 | 1157 | ||
| 1087 | static unsigned int azx_max_codecs[] __devinitdata = { | 1158 | static unsigned int azx_max_codecs[] __devinitdata = { |
| 1088 | [AZX_DRIVER_ICH] = 3, | 1159 | [AZX_DRIVER_ICH] = 4, /* Some ICH9 boards use SD3 */ |
| 1089 | [AZX_DRIVER_SCH] = 3, | 1160 | [AZX_DRIVER_SCH] = 3, |
| 1090 | [AZX_DRIVER_ATI] = 4, | 1161 | [AZX_DRIVER_ATI] = 4, |
| 1091 | [AZX_DRIVER_ATIHDMI] = 4, | 1162 | [AZX_DRIVER_ATIHDMI] = 4, |
| @@ -1093,6 +1164,7 @@ static unsigned int azx_max_codecs[] __devinitdata = { | |||
| 1093 | [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */ | 1164 | [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */ |
| 1094 | [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */ | 1165 | [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */ |
| 1095 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ | 1166 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ |
| 1167 | [AZX_DRIVER_TERA] = 1, | ||
| 1096 | }; | 1168 | }; |
| 1097 | 1169 | ||
| 1098 | static int __devinit azx_codec_create(struct azx *chip, const char *model, | 1170 | static int __devinit azx_codec_create(struct azx *chip, const char *model, |
| @@ -1316,7 +1388,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 1316 | 1388 | ||
| 1317 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", | 1389 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", |
| 1318 | azx_dev->bufsize, azx_dev->format_val); | 1390 | azx_dev->bufsize, azx_dev->format_val); |
| 1319 | if (azx_setup_periods(substream, azx_dev) < 0) | 1391 | if (azx_setup_periods(chip, substream, azx_dev) < 0) |
| 1320 | return -EINVAL; | 1392 | return -EINVAL; |
| 1321 | azx_setup_controller(chip, azx_dev); | 1393 | azx_setup_controller(chip, azx_dev); |
| 1322 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 1394 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| @@ -1421,35 +1493,113 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1421 | return 0; | 1493 | return 0; |
| 1422 | } | 1494 | } |
| 1423 | 1495 | ||
| 1424 | static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | 1496 | static unsigned int azx_get_position(struct azx *chip, |
| 1497 | struct azx_dev *azx_dev) | ||
| 1425 | { | 1498 | { |
| 1426 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
| 1427 | struct azx *chip = apcm->chip; | ||
| 1428 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
| 1429 | unsigned int pos; | 1499 | unsigned int pos; |
| 1430 | 1500 | ||
| 1431 | if (chip->position_fix == POS_FIX_POSBUF || | 1501 | if (chip->position_fix == POS_FIX_POSBUF || |
| 1432 | chip->position_fix == POS_FIX_AUTO) { | 1502 | chip->position_fix == POS_FIX_AUTO) { |
| 1433 | /* use the position buffer */ | 1503 | /* use the position buffer */ |
| 1434 | pos = le32_to_cpu(*azx_dev->posbuf); | 1504 | pos = le32_to_cpu(*azx_dev->posbuf); |
| 1435 | if (chip->position_fix == POS_FIX_AUTO && | ||
| 1436 | azx_dev->period_intr == 1 && !pos) { | ||
| 1437 | printk(KERN_WARNING | ||
| 1438 | "hda-intel: Invalid position buffer, " | ||
| 1439 | "using LPIB read method instead.\n"); | ||
| 1440 | chip->position_fix = POS_FIX_NONE; | ||
| 1441 | goto read_lpib; | ||
| 1442 | } | ||
| 1443 | } else { | 1505 | } else { |
| 1444 | read_lpib: | ||
| 1445 | /* read LPIB */ | 1506 | /* read LPIB */ |
| 1446 | pos = azx_sd_readl(azx_dev, SD_LPIB); | 1507 | pos = azx_sd_readl(azx_dev, SD_LPIB); |
| 1447 | if (chip->position_fix == POS_FIX_FIFO) | ||
| 1448 | pos += azx_dev->fifo_size; | ||
| 1449 | } | 1508 | } |
| 1450 | if (pos >= azx_dev->bufsize) | 1509 | if (pos >= azx_dev->bufsize) |
| 1451 | pos = 0; | 1510 | pos = 0; |
| 1452 | return bytes_to_frames(substream->runtime, pos); | 1511 | return pos; |
| 1512 | } | ||
| 1513 | |||
| 1514 | static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | ||
| 1515 | { | ||
| 1516 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
| 1517 | struct azx *chip = apcm->chip; | ||
| 1518 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
| 1519 | return bytes_to_frames(substream->runtime, | ||
| 1520 | azx_get_position(chip, azx_dev)); | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | /* | ||
| 1524 | * Check whether the current DMA position is acceptable for updating | ||
| 1525 | * periods. Returns non-zero if it's OK. | ||
| 1526 | * | ||
| 1527 | * Many HD-audio controllers appear pretty inaccurate about | ||
| 1528 | * the update-IRQ timing. The IRQ is issued before actually the | ||
| 1529 | * data is processed. So, we need to process it afterwords in a | ||
| 1530 | * workqueue. | ||
| 1531 | */ | ||
| 1532 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | ||
| 1533 | { | ||
| 1534 | unsigned int pos; | ||
| 1535 | |||
| 1536 | pos = azx_get_position(chip, azx_dev); | ||
| 1537 | if (chip->position_fix == POS_FIX_AUTO) { | ||
| 1538 | if (!pos) { | ||
| 1539 | printk(KERN_WARNING | ||
| 1540 | "hda-intel: Invalid position buffer, " | ||
| 1541 | "using LPIB read method instead.\n"); | ||
| 1542 | chip->position_fix = POS_FIX_LPIB; | ||
| 1543 | pos = azx_get_position(chip, azx_dev); | ||
| 1544 | } else | ||
| 1545 | chip->position_fix = POS_FIX_POSBUF; | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) | ||
| 1549 | return 0; /* NG - it's below the period boundary */ | ||
| 1550 | return 1; /* OK, it's fine */ | ||
| 1551 | } | ||
| 1552 | |||
| 1553 | /* | ||
| 1554 | * The work for pending PCM period updates. | ||
| 1555 | */ | ||
| 1556 | static void azx_irq_pending_work(struct work_struct *work) | ||
| 1557 | { | ||
| 1558 | struct azx *chip = container_of(work, struct azx, irq_pending_work); | ||
| 1559 | int i, pending; | ||
| 1560 | |||
| 1561 | if (!chip->irq_pending_warned) { | ||
| 1562 | printk(KERN_WARNING | ||
| 1563 | "hda-intel: IRQ timing workaround is activated " | ||
| 1564 | "for card #%d. Suggest a bigger bdl_pos_adj.\n", | ||
| 1565 | chip->card->number); | ||
| 1566 | chip->irq_pending_warned = 1; | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | for (;;) { | ||
| 1570 | pending = 0; | ||
| 1571 | spin_lock_irq(&chip->reg_lock); | ||
| 1572 | for (i = 0; i < chip->num_streams; i++) { | ||
| 1573 | struct azx_dev *azx_dev = &chip->azx_dev[i]; | ||
| 1574 | if (!azx_dev->irq_pending || | ||
| 1575 | !azx_dev->substream || | ||
| 1576 | !azx_dev->running) | ||
| 1577 | continue; | ||
| 1578 | if (azx_position_ok(chip, azx_dev)) { | ||
| 1579 | azx_dev->irq_pending = 0; | ||
| 1580 | spin_unlock(&chip->reg_lock); | ||
| 1581 | snd_pcm_period_elapsed(azx_dev->substream); | ||
| 1582 | spin_lock(&chip->reg_lock); | ||
| 1583 | } else | ||
| 1584 | pending++; | ||
| 1585 | } | ||
| 1586 | spin_unlock_irq(&chip->reg_lock); | ||
| 1587 | if (!pending) | ||
| 1588 | return; | ||
| 1589 | cond_resched(); | ||
| 1590 | } | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | /* clear irq_pending flags and assure no on-going workq */ | ||
| 1594 | static void azx_clear_irq_pending(struct azx *chip) | ||
| 1595 | { | ||
| 1596 | int i; | ||
| 1597 | |||
| 1598 | spin_lock_irq(&chip->reg_lock); | ||
| 1599 | for (i = 0; i < chip->num_streams; i++) | ||
| 1600 | chip->azx_dev[i].irq_pending = 0; | ||
| 1601 | spin_unlock_irq(&chip->reg_lock); | ||
| 1602 | flush_scheduled_work(); | ||
| 1453 | } | 1603 | } |
| 1454 | 1604 | ||
| 1455 | static struct snd_pcm_ops azx_pcm_ops = { | 1605 | static struct snd_pcm_ops azx_pcm_ops = { |
| @@ -1676,6 +1826,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
| 1676 | int i; | 1826 | int i; |
| 1677 | 1827 | ||
| 1678 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 1828 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
| 1829 | azx_clear_irq_pending(chip); | ||
| 1679 | for (i = 0; i < AZX_MAX_PCMS; i++) | 1830 | for (i = 0; i < AZX_MAX_PCMS; i++) |
| 1680 | snd_pcm_suspend_all(chip->pcm[i]); | 1831 | snd_pcm_suspend_all(chip->pcm[i]); |
| 1681 | if (chip->initialized) | 1832 | if (chip->initialized) |
| @@ -1732,6 +1883,7 @@ static int azx_free(struct azx *chip) | |||
| 1732 | int i; | 1883 | int i; |
| 1733 | 1884 | ||
| 1734 | if (chip->initialized) { | 1885 | if (chip->initialized) { |
| 1886 | azx_clear_irq_pending(chip); | ||
| 1735 | for (i = 0; i < chip->num_streams; i++) | 1887 | for (i = 0; i < chip->num_streams; i++) |
| 1736 | azx_stream_stop(chip, &chip->azx_dev[i]); | 1888 | azx_stream_stop(chip, &chip->azx_dev[i]); |
| 1737 | azx_stop_chip(chip); | 1889 | azx_stop_chip(chip); |
| @@ -1770,9 +1922,9 @@ static int azx_dev_free(struct snd_device *device) | |||
| 1770 | * white/black-listing for position_fix | 1922 | * white/black-listing for position_fix |
| 1771 | */ | 1923 | */ |
| 1772 | static struct snd_pci_quirk position_fix_list[] __devinitdata = { | 1924 | static struct snd_pci_quirk position_fix_list[] __devinitdata = { |
| 1773 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), | 1925 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), |
| 1774 | SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE), | 1926 | SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), |
| 1775 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_NONE), | 1927 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), |
| 1776 | {} | 1928 | {} |
| 1777 | }; | 1929 | }; |
| 1778 | 1930 | ||
| @@ -1857,12 +2009,25 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
| 1857 | chip->irq = -1; | 2009 | chip->irq = -1; |
| 1858 | chip->driver_type = driver_type; | 2010 | chip->driver_type = driver_type; |
| 1859 | chip->msi = enable_msi; | 2011 | chip->msi = enable_msi; |
| 2012 | chip->dev_index = dev; | ||
| 2013 | INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); | ||
| 1860 | 2014 | ||
| 1861 | chip->position_fix = check_position_fix(chip, position_fix[dev]); | 2015 | chip->position_fix = check_position_fix(chip, position_fix[dev]); |
| 1862 | check_probe_mask(chip, dev); | 2016 | check_probe_mask(chip, dev); |
| 1863 | 2017 | ||
| 1864 | chip->single_cmd = single_cmd; | 2018 | chip->single_cmd = single_cmd; |
| 1865 | 2019 | ||
| 2020 | if (bdl_pos_adj[dev] < 0) { | ||
| 2021 | switch (chip->driver_type) { | ||
| 2022 | case AZX_DRIVER_ICH: | ||
| 2023 | bdl_pos_adj[dev] = 1; | ||
| 2024 | break; | ||
| 2025 | default: | ||
| 2026 | bdl_pos_adj[dev] = 32; | ||
| 2027 | break; | ||
| 2028 | } | ||
| 2029 | } | ||
| 2030 | |||
| 1866 | #if BITS_PER_LONG != 64 | 2031 | #if BITS_PER_LONG != 64 |
| 1867 | /* Fix up base address on ULI M5461 */ | 2032 | /* Fix up base address on ULI M5461 */ |
| 1868 | if (chip->driver_type == AZX_DRIVER_ULI) { | 2033 | if (chip->driver_type == AZX_DRIVER_ULI) { |
| @@ -2089,6 +2254,7 @@ static struct pci_device_id azx_ids[] = { | |||
| 2089 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, | 2254 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, |
| 2090 | { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH }, | 2255 | { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH }, |
| 2091 | { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH }, | 2256 | { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH }, |
| 2257 | { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH }, | ||
| 2092 | { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH }, | 2258 | { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH }, |
| 2093 | { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH }, | 2259 | { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH }, |
| 2094 | { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH }, | 2260 | { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH }, |
| @@ -2141,6 +2307,8 @@ static struct pci_device_id azx_ids[] = { | |||
| 2141 | { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, | 2307 | { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, |
| 2142 | { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, | 2308 | { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, |
| 2143 | { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, | 2309 | { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, |
| 2310 | /* Teradici */ | ||
| 2311 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | ||
| 2144 | { 0, } | 2312 | { 0, } |
| 2145 | }; | 2313 | }; |
| 2146 | MODULE_DEVICE_TABLE(pci, azx_ids); | 2314 | MODULE_DEVICE_TABLE(pci, azx_ids); |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 5633f77f8f3b..1e5aff5c48d1 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
| @@ -366,8 +366,6 @@ static void print_digital_conv(struct snd_info_buffer *buffer, | |||
| 366 | { | 366 | { |
| 367 | unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, | 367 | unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, |
| 368 | AC_VERB_GET_DIGI_CONVERT_1, 0); | 368 | AC_VERB_GET_DIGI_CONVERT_1, 0); |
| 369 | unsigned int digi2 = snd_hda_codec_read(codec, nid, 0, | ||
| 370 | AC_VERB_GET_DIGI_CONVERT_2, 0); | ||
| 371 | snd_iprintf(buffer, " Digital:"); | 369 | snd_iprintf(buffer, " Digital:"); |
| 372 | if (digi1 & AC_DIG1_ENABLE) | 370 | if (digi1 & AC_DIG1_ENABLE) |
| 373 | snd_iprintf(buffer, " Enabled"); | 371 | snd_iprintf(buffer, " Enabled"); |
| @@ -386,7 +384,8 @@ static void print_digital_conv(struct snd_info_buffer *buffer, | |||
| 386 | if (digi1 & AC_DIG1_LEVEL) | 384 | if (digi1 & AC_DIG1_LEVEL) |
| 387 | snd_iprintf(buffer, " GenLevel"); | 385 | snd_iprintf(buffer, " GenLevel"); |
| 388 | snd_iprintf(buffer, "\n"); | 386 | snd_iprintf(buffer, "\n"); |
| 389 | snd_iprintf(buffer, " Digital category: 0x%x\n", digi2 & AC_DIG2_CC); | 387 | snd_iprintf(buffer, " Digital category: 0x%x\n", |
| 388 | (digi1 >> 8) & AC_DIG2_CC); | ||
| 390 | } | 389 | } |
| 391 | 390 | ||
| 392 | static const char *get_pwr_state(u32 state) | 391 | static const char *get_pwr_state(u32 state) |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index a99e86d74278..e8003d99f0bf 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
| 26 | #include <linux/mutex.h> | ||
| 27 | 26 | ||
| 28 | #include <sound/core.h> | 27 | #include <sound/core.h> |
| 29 | #include "hda_codec.h" | 28 | #include "hda_codec.h" |
| @@ -64,7 +63,6 @@ struct ad198x_spec { | |||
| 64 | /* PCM information */ | 63 | /* PCM information */ |
| 65 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | 64 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ |
| 66 | 65 | ||
| 67 | struct mutex amp_mutex; /* PCM volume/mute control mutex */ | ||
| 68 | unsigned int spdif_route; | 66 | unsigned int spdif_route; |
| 69 | 67 | ||
| 70 | /* dynamic controls, init_verbs and input_mux */ | 68 | /* dynamic controls, init_verbs and input_mux */ |
| @@ -1618,6 +1616,7 @@ static const char *ad1981_models[AD1981_MODELS] = { | |||
| 1618 | 1616 | ||
| 1619 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { | 1617 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { |
| 1620 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | 1618 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), |
| 1619 | SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), | ||
| 1621 | /* All HP models */ | 1620 | /* All HP models */ |
| 1622 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), | 1621 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), |
| 1623 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | 1622 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), |
| @@ -2623,7 +2622,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | |||
| 2623 | { | 2622 | { |
| 2624 | struct ad198x_spec *spec = codec->spec; | 2623 | struct ad198x_spec *spec = codec->spec; |
| 2625 | hda_nid_t nid; | 2624 | hda_nid_t nid; |
| 2626 | int idx, err; | 2625 | int i, idx, err; |
| 2627 | char name[32]; | 2626 | char name[32]; |
| 2628 | 2627 | ||
| 2629 | if (! pin) | 2628 | if (! pin) |
| @@ -2631,16 +2630,26 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | |||
| 2631 | 2630 | ||
| 2632 | idx = ad1988_pin_idx(pin); | 2631 | idx = ad1988_pin_idx(pin); |
| 2633 | nid = ad1988_idx_to_dac(codec, idx); | 2632 | nid = ad1988_idx_to_dac(codec, idx); |
| 2634 | /* specify the DAC as the extra output */ | 2633 | /* check whether the corresponding DAC was already taken */ |
| 2635 | if (! spec->multiout.hp_nid) | 2634 | for (i = 0; i < spec->autocfg.line_outs; i++) { |
| 2636 | spec->multiout.hp_nid = nid; | 2635 | hda_nid_t pin = spec->autocfg.line_out_pins[i]; |
| 2637 | else | 2636 | hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin)); |
| 2638 | spec->multiout.extra_out_nid[0] = nid; | 2637 | if (dac == nid) |
| 2639 | /* control HP volume/switch on the output mixer amp */ | 2638 | break; |
| 2640 | sprintf(name, "%s Playback Volume", pfx); | 2639 | } |
| 2641 | if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, | 2640 | if (i >= spec->autocfg.line_outs) { |
| 2642 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 2641 | /* specify the DAC as the extra output */ |
| 2643 | return err; | 2642 | if (!spec->multiout.hp_nid) |
| 2643 | spec->multiout.hp_nid = nid; | ||
| 2644 | else | ||
| 2645 | spec->multiout.extra_out_nid[0] = nid; | ||
| 2646 | /* control HP volume/switch on the output mixer amp */ | ||
| 2647 | sprintf(name, "%s Playback Volume", pfx); | ||
| 2648 | err = add_control(spec, AD_CTL_WIDGET_VOL, name, | ||
| 2649 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
| 2650 | if (err < 0) | ||
| 2651 | return err; | ||
| 2652 | } | ||
| 2644 | nid = ad1988_mixer_nids[idx]; | 2653 | nid = ad1988_mixer_nids[idx]; |
| 2645 | sprintf(name, "%s Playback Switch", pfx); | 2654 | sprintf(name, "%s Playback Switch", pfx); |
| 2646 | if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, | 2655 | if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, |
| @@ -3177,7 +3186,6 @@ static int patch_ad1884(struct hda_codec *codec) | |||
| 3177 | if (spec == NULL) | 3186 | if (spec == NULL) |
| 3178 | return -ENOMEM; | 3187 | return -ENOMEM; |
| 3179 | 3188 | ||
| 3180 | mutex_init(&spec->amp_mutex); | ||
| 3181 | codec->spec = spec; | 3189 | codec->spec = spec; |
| 3182 | 3190 | ||
| 3183 | spec->multiout.max_channels = 2; | 3191 | spec->multiout.max_channels = 2; |
| @@ -3847,7 +3855,6 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
| 3847 | if (spec == NULL) | 3855 | if (spec == NULL) |
| 3848 | return -ENOMEM; | 3856 | return -ENOMEM; |
| 3849 | 3857 | ||
| 3850 | mutex_init(&spec->amp_mutex); | ||
| 3851 | codec->spec = spec; | 3858 | codec->spec = spec; |
| 3852 | 3859 | ||
| 3853 | spec->multiout.max_channels = 2; | 3860 | spec->multiout.max_channels = 2; |
| @@ -4152,7 +4159,6 @@ static int patch_ad1882(struct hda_codec *codec) | |||
| 4152 | if (spec == NULL) | 4159 | if (spec == NULL) |
| 4153 | return -ENOMEM; | 4160 | return -ENOMEM; |
| 4154 | 4161 | ||
| 4155 | mutex_init(&spec->amp_mutex); | ||
| 4156 | codec->spec = spec; | 4162 | codec->spec = spec; |
| 4157 | 4163 | ||
| 4158 | spec->multiout.max_channels = 6; | 4164 | spec->multiout.max_channels = 6; |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 36fd85260035..7c1eb23f0cec 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
| @@ -82,7 +82,6 @@ struct conexant_spec { | |||
| 82 | /* PCM information */ | 82 | /* PCM information */ |
| 83 | struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ | 83 | struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ |
| 84 | 84 | ||
| 85 | struct mutex amp_mutex; /* PCM volume/mute control mutex */ | ||
| 86 | unsigned int spdif_route; | 85 | unsigned int spdif_route; |
| 87 | 86 | ||
| 88 | /* dynamic controls, init_verbs and input_mux */ | 87 | /* dynamic controls, init_verbs and input_mux */ |
| @@ -687,7 +686,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { | |||
| 687 | 686 | ||
| 688 | static struct hda_verb cxt5045_init_verbs[] = { | 687 | static struct hda_verb cxt5045_init_verbs[] = { |
| 689 | /* Line in, Mic */ | 688 | /* Line in, Mic */ |
| 690 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | 689 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
| 691 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | 690 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
| 692 | /* HP, Amp */ | 691 | /* HP, Amp */ |
| 693 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 692 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
| @@ -907,10 +906,12 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | |||
| 907 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), | 906 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), |
| 908 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), | 907 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), |
| 909 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), | 908 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), |
| 909 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), | ||
| 910 | SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), | 910 | SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), |
| 911 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), | 911 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), |
| 912 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), | 912 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), |
| 913 | SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE), | 913 | SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", |
| 914 | CXT5045_LAPTOP_HPMICSENSE), | ||
| 914 | SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), | 915 | SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), |
| 915 | SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), | 916 | SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), |
| 916 | SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), | 917 | SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), |
| @@ -928,7 +929,6 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
| 928 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 929 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
| 929 | if (!spec) | 930 | if (!spec) |
| 930 | return -ENOMEM; | 931 | return -ENOMEM; |
| 931 | mutex_init(&spec->amp_mutex); | ||
| 932 | codec->spec = spec; | 932 | codec->spec = spec; |
| 933 | 933 | ||
| 934 | spec->multiout.max_channels = 2; | 934 | spec->multiout.max_channels = 2; |
| @@ -963,6 +963,7 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
| 963 | codec->patch_ops.init = cxt5045_init; | 963 | codec->patch_ops.init = cxt5045_init; |
| 964 | break; | 964 | break; |
| 965 | case CXT5045_LAPTOP_MICSENSE: | 965 | case CXT5045_LAPTOP_MICSENSE: |
| 966 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
| 966 | spec->input_mux = &cxt5045_capture_source; | 967 | spec->input_mux = &cxt5045_capture_source; |
| 967 | spec->num_init_verbs = 2; | 968 | spec->num_init_verbs = 2; |
| 968 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; | 969 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; |
| @@ -1007,15 +1008,19 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
| 1007 | #endif | 1008 | #endif |
| 1008 | } | 1009 | } |
| 1009 | 1010 | ||
| 1010 | /* | 1011 | switch (codec->subsystem_id >> 16) { |
| 1011 | * Fix max PCM level to 0 dB | 1012 | case 0x103c: |
| 1012 | * (originall it has 0x2b steps with 0dB offset 0x14) | 1013 | /* HP laptop has a really bad sound over 0dB on NID 0x17. |
| 1013 | */ | 1014 | * Fix max PCM level to 0 dB |
| 1014 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, | 1015 | * (originall it has 0x2b steps with 0dB offset 0x14) |
| 1015 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | | 1016 | */ |
| 1016 | (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | | 1017 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, |
| 1017 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | 1018 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | |
| 1018 | (1 << AC_AMPCAP_MUTE_SHIFT)); | 1019 | (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | |
| 1020 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
| 1021 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
| 1022 | break; | ||
| 1023 | } | ||
| 1019 | 1024 | ||
| 1020 | return 0; | 1025 | return 0; |
| 1021 | } | 1026 | } |
| @@ -1477,7 +1482,6 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
| 1477 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1482 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
| 1478 | if (!spec) | 1483 | if (!spec) |
| 1479 | return -ENOMEM; | 1484 | return -ENOMEM; |
| 1480 | mutex_init(&spec->amp_mutex); | ||
| 1481 | codec->spec = spec; | 1485 | codec->spec = spec; |
| 1482 | 1486 | ||
| 1483 | spec->multiout.max_channels = 2; | 1487 | spec->multiout.max_channels = 2; |
| @@ -1736,7 +1740,6 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
| 1736 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1740 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
| 1737 | if (!spec) | 1741 | if (!spec) |
| 1738 | return -ENOMEM; | 1742 | return -ENOMEM; |
| 1739 | mutex_init(&spec->amp_mutex); | ||
| 1740 | codec->spec = spec; | 1743 | codec->spec = spec; |
| 1741 | 1744 | ||
| 1742 | codec->patch_ops = conexant_patch_ops; | 1745 | codec->patch_ops = conexant_patch_ops; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b0a2a262ece2..2807bc840d26 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
| @@ -163,6 +163,10 @@ enum { | |||
| 163 | ALC662_LENOVO_101E, | 163 | ALC662_LENOVO_101E, |
| 164 | ALC662_ASUS_EEEPC_P701, | 164 | ALC662_ASUS_EEEPC_P701, |
| 165 | ALC662_ASUS_EEEPC_EP20, | 165 | ALC662_ASUS_EEEPC_EP20, |
| 166 | ALC663_ASUS_M51VA, | ||
| 167 | ALC663_ASUS_G71V, | ||
| 168 | ALC663_ASUS_H13, | ||
| 169 | ALC663_ASUS_G50V, | ||
| 166 | ALC662_AUTO, | 170 | ALC662_AUTO, |
| 167 | ALC662_MODEL_LAST, | 171 | ALC662_MODEL_LAST, |
| 168 | }; | 172 | }; |
| @@ -205,6 +209,7 @@ enum { | |||
| 205 | ALC883_MITAC, | 209 | ALC883_MITAC, |
| 206 | ALC883_CLEVO_M720, | 210 | ALC883_CLEVO_M720, |
| 207 | ALC883_FUJITSU_PI2515, | 211 | ALC883_FUJITSU_PI2515, |
| 212 | ALC883_3ST_6ch_INTEL, | ||
| 208 | ALC883_AUTO, | 213 | ALC883_AUTO, |
| 209 | ALC883_MODEL_LAST, | 214 | ALC883_MODEL_LAST, |
| 210 | }; | 215 | }; |
| @@ -280,6 +285,10 @@ struct alc_spec { | |||
| 280 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 285 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 281 | struct hda_loopback_check loopback; | 286 | struct hda_loopback_check loopback; |
| 282 | #endif | 287 | #endif |
| 288 | |||
| 289 | /* for PLL fix */ | ||
| 290 | hda_nid_t pll_nid; | ||
| 291 | unsigned int pll_coef_idx, pll_coef_bit; | ||
| 283 | }; | 292 | }; |
| 284 | 293 | ||
| 285 | /* | 294 | /* |
| @@ -747,6 +756,38 @@ static struct hda_verb alc_gpio3_init_verbs[] = { | |||
| 747 | { } | 756 | { } |
| 748 | }; | 757 | }; |
| 749 | 758 | ||
| 759 | /* | ||
| 760 | * Fix hardware PLL issue | ||
| 761 | * On some codecs, the analog PLL gating control must be off while | ||
| 762 | * the default value is 1. | ||
| 763 | */ | ||
| 764 | static void alc_fix_pll(struct hda_codec *codec) | ||
| 765 | { | ||
| 766 | struct alc_spec *spec = codec->spec; | ||
| 767 | unsigned int val; | ||
| 768 | |||
| 769 | if (!spec->pll_nid) | ||
| 770 | return; | ||
| 771 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, | ||
| 772 | spec->pll_coef_idx); | ||
| 773 | val = snd_hda_codec_read(codec, spec->pll_nid, 0, | ||
| 774 | AC_VERB_GET_PROC_COEF, 0); | ||
| 775 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, | ||
| 776 | spec->pll_coef_idx); | ||
| 777 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, | ||
| 778 | val & ~(1 << spec->pll_coef_bit)); | ||
| 779 | } | ||
| 780 | |||
| 781 | static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, | ||
| 782 | unsigned int coef_idx, unsigned int coef_bit) | ||
| 783 | { | ||
| 784 | struct alc_spec *spec = codec->spec; | ||
| 785 | spec->pll_nid = nid; | ||
| 786 | spec->pll_coef_idx = coef_idx; | ||
| 787 | spec->pll_coef_bit = coef_bit; | ||
| 788 | alc_fix_pll(codec); | ||
| 789 | } | ||
| 790 | |||
| 750 | static void alc_sku_automute(struct hda_codec *codec) | 791 | static void alc_sku_automute(struct hda_codec *codec) |
| 751 | { | 792 | { |
| 752 | struct alc_spec *spec = codec->spec; | 793 | struct alc_spec *spec = codec->spec; |
| @@ -776,6 +817,24 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) | |||
| 776 | alc_sku_automute(codec); | 817 | alc_sku_automute(codec); |
| 777 | } | 818 | } |
| 778 | 819 | ||
| 820 | /* additional initialization for ALC888 variants */ | ||
| 821 | static void alc888_coef_init(struct hda_codec *codec) | ||
| 822 | { | ||
| 823 | unsigned int tmp; | ||
| 824 | |||
| 825 | snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0); | ||
| 826 | tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); | ||
| 827 | snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); | ||
| 828 | if ((tmp & 0xf0) == 2) | ||
| 829 | /* alc888S-VC */ | ||
| 830 | snd_hda_codec_read(codec, 0x20, 0, | ||
| 831 | AC_VERB_SET_PROC_COEF, 0x830); | ||
| 832 | else | ||
| 833 | /* alc888-VB */ | ||
| 834 | snd_hda_codec_read(codec, 0x20, 0, | ||
| 835 | AC_VERB_SET_PROC_COEF, 0x3030); | ||
| 836 | } | ||
| 837 | |||
| 779 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. | 838 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. |
| 780 | * 31 ~ 16 : Manufacture ID | 839 | * 31 ~ 16 : Manufacture ID |
| 781 | * 15 ~ 8 : SKU ID | 840 | * 15 ~ 8 : SKU ID |
| @@ -851,8 +910,10 @@ do_sku: | |||
| 851 | case 0x10ec0267: | 910 | case 0x10ec0267: |
| 852 | case 0x10ec0268: | 911 | case 0x10ec0268: |
| 853 | case 0x10ec0269: | 912 | case 0x10ec0269: |
| 913 | case 0x10ec0660: | ||
| 914 | case 0x10ec0662: | ||
| 915 | case 0x10ec0663: | ||
| 854 | case 0x10ec0862: | 916 | case 0x10ec0862: |
| 855 | case 0x10ec0662: | ||
| 856 | case 0x10ec0889: | 917 | case 0x10ec0889: |
| 857 | snd_hda_codec_write(codec, 0x14, 0, | 918 | snd_hda_codec_write(codec, 0x14, 0, |
| 858 | AC_VERB_SET_EAPD_BTLENABLE, 2); | 919 | AC_VERB_SET_EAPD_BTLENABLE, 2); |
| @@ -877,7 +938,6 @@ do_sku: | |||
| 877 | case 0x10ec0882: | 938 | case 0x10ec0882: |
| 878 | case 0x10ec0883: | 939 | case 0x10ec0883: |
| 879 | case 0x10ec0885: | 940 | case 0x10ec0885: |
| 880 | case 0x10ec0888: | ||
| 881 | case 0x10ec0889: | 941 | case 0x10ec0889: |
| 882 | snd_hda_codec_write(codec, 0x20, 0, | 942 | snd_hda_codec_write(codec, 0x20, 0, |
| 883 | AC_VERB_SET_COEF_INDEX, 7); | 943 | AC_VERB_SET_COEF_INDEX, 7); |
| @@ -889,6 +949,9 @@ do_sku: | |||
| 889 | AC_VERB_SET_PROC_COEF, | 949 | AC_VERB_SET_PROC_COEF, |
| 890 | tmp | 0x2010); | 950 | tmp | 0x2010); |
| 891 | break; | 951 | break; |
| 952 | case 0x10ec0888: | ||
| 953 | alc888_coef_init(codec); | ||
| 954 | break; | ||
| 892 | case 0x10ec0267: | 955 | case 0x10ec0267: |
| 893 | case 0x10ec0268: | 956 | case 0x10ec0268: |
| 894 | snd_hda_codec_write(codec, 0x20, 0, | 957 | snd_hda_codec_write(codec, 0x20, 0, |
| @@ -2373,6 +2436,8 @@ static int alc_init(struct hda_codec *codec) | |||
| 2373 | struct alc_spec *spec = codec->spec; | 2436 | struct alc_spec *spec = codec->spec; |
| 2374 | unsigned int i; | 2437 | unsigned int i; |
| 2375 | 2438 | ||
| 2439 | alc_fix_pll(codec); | ||
| 2440 | |||
| 2376 | for (i = 0; i < spec->num_init_verbs; i++) | 2441 | for (i = 0; i < spec->num_init_verbs; i++) |
| 2377 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | 2442 | snd_hda_sequence_write(codec, spec->init_verbs[i]); |
| 2378 | 2443 | ||
| @@ -3009,6 +3074,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { | |||
| 3009 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), | 3074 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), |
| 3010 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), | 3075 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), |
| 3011 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), | 3076 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), |
| 3077 | SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), | ||
| 3012 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), | 3078 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), |
| 3013 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), | 3079 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), |
| 3014 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), | 3080 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), |
| @@ -5101,7 +5167,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { | |||
| 5101 | SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), | 5167 | SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), |
| 5102 | SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), | 5168 | SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), |
| 5103 | SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), | 5169 | SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), |
| 5104 | SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP), | 5170 | SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), |
| 5105 | SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), | 5171 | SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), |
| 5106 | SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), | 5172 | SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), |
| 5107 | SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), | 5173 | SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), |
| @@ -6127,6 +6193,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { | |||
| 6127 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), | 6193 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), |
| 6128 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), | 6194 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), |
| 6129 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), | 6195 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), |
| 6196 | SND_PCI_QUIRK(0x106b, 0x00a0, "Apple iMac 24''", ALC885_IMAC24), | ||
| 6130 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), | 6197 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), |
| 6131 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ | 6198 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ |
| 6132 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), | 6199 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), |
| @@ -6353,7 +6420,9 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) | |||
| 6353 | continue; | 6420 | continue; |
| 6354 | vref = PIN_IN; | 6421 | vref = PIN_IN; |
| 6355 | if (1 /*i <= AUTO_PIN_FRONT_MIC*/) { | 6422 | if (1 /*i <= AUTO_PIN_FRONT_MIC*/) { |
| 6356 | if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) & | 6423 | unsigned int pincap; |
| 6424 | pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
| 6425 | if ((pincap >> AC_PINCAP_VREF_SHIFT) & | ||
| 6357 | AC_PINCAP_VREF_80) | 6426 | AC_PINCAP_VREF_80) |
| 6358 | vref = PIN_VREF80; | 6427 | vref = PIN_VREF80; |
| 6359 | } | 6428 | } |
| @@ -6450,8 +6519,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
| 6450 | case 0x106b1000: /* iMac 24 */ | 6519 | case 0x106b1000: /* iMac 24 */ |
| 6451 | board_config = ALC885_IMAC24; | 6520 | board_config = ALC885_IMAC24; |
| 6452 | break; | 6521 | break; |
| 6453 | case 0x106b00a1: /* Macbook */ | 6522 | case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ |
| 6454 | case 0x106b2c00: /* Macbook Pro rev3 */ | 6523 | case 0x106b2c00: /* Macbook Pro rev3 */ |
| 6524 | case 0x106b3600: /* Macbook 3.1 */ | ||
| 6455 | board_config = ALC885_MBP3; | 6525 | board_config = ALC885_MBP3; |
| 6456 | break; | 6526 | break; |
| 6457 | default: | 6527 | default: |
| @@ -6485,14 +6555,20 @@ static int patch_alc882(struct hda_codec *codec) | |||
| 6485 | if (board_config != ALC882_AUTO) | 6555 | if (board_config != ALC882_AUTO) |
| 6486 | setup_preset(spec, &alc882_presets[board_config]); | 6556 | setup_preset(spec, &alc882_presets[board_config]); |
| 6487 | 6557 | ||
| 6488 | spec->stream_name_analog = "ALC882 Analog"; | 6558 | if (codec->vendor_id == 0x10ec0885) { |
| 6559 | spec->stream_name_analog = "ALC885 Analog"; | ||
| 6560 | spec->stream_name_digital = "ALC885 Digital"; | ||
| 6561 | } else { | ||
| 6562 | spec->stream_name_analog = "ALC882 Analog"; | ||
| 6563 | spec->stream_name_digital = "ALC882 Digital"; | ||
| 6564 | } | ||
| 6565 | |||
| 6489 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 6566 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
| 6490 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 6567 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
| 6491 | /* FIXME: setup DAC5 */ | 6568 | /* FIXME: setup DAC5 */ |
| 6492 | /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ | 6569 | /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ |
| 6493 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | 6570 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; |
| 6494 | 6571 | ||
| 6495 | spec->stream_name_digital = "ALC882 Digital"; | ||
| 6496 | spec->stream_digital_playback = &alc882_pcm_digital_playback; | 6572 | spec->stream_digital_playback = &alc882_pcm_digital_playback; |
| 6497 | spec->stream_digital_capture = &alc882_pcm_digital_capture; | 6573 | spec->stream_digital_capture = &alc882_pcm_digital_capture; |
| 6498 | 6574 | ||
| @@ -6569,6 +6645,16 @@ static struct hda_input_mux alc883_capture_source = { | |||
| 6569 | }, | 6645 | }, |
| 6570 | }; | 6646 | }; |
| 6571 | 6647 | ||
| 6648 | static struct hda_input_mux alc883_3stack_6ch_intel = { | ||
| 6649 | .num_items = 4, | ||
| 6650 | .items = { | ||
| 6651 | { "Mic", 0x1 }, | ||
| 6652 | { "Front Mic", 0x0 }, | ||
| 6653 | { "Line", 0x2 }, | ||
| 6654 | { "CD", 0x4 }, | ||
| 6655 | }, | ||
| 6656 | }; | ||
| 6657 | |||
| 6572 | static struct hda_input_mux alc883_lenovo_101e_capture_source = { | 6658 | static struct hda_input_mux alc883_lenovo_101e_capture_source = { |
| 6573 | .num_items = 2, | 6659 | .num_items = 2, |
| 6574 | .items = { | 6660 | .items = { |
| @@ -6650,6 +6736,48 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { | |||
| 6650 | }; | 6736 | }; |
| 6651 | 6737 | ||
| 6652 | /* | 6738 | /* |
| 6739 | * 2ch mode | ||
| 6740 | */ | ||
| 6741 | static struct hda_verb alc883_3ST_ch2_intel_init[] = { | ||
| 6742 | { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
| 6743 | { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
| 6744 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
| 6745 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
| 6746 | { } /* end */ | ||
| 6747 | }; | ||
| 6748 | |||
| 6749 | /* | ||
| 6750 | * 4ch mode | ||
| 6751 | */ | ||
| 6752 | static struct hda_verb alc883_3ST_ch4_intel_init[] = { | ||
| 6753 | { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
| 6754 | { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
| 6755 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
| 6756 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
| 6757 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
| 6758 | { } /* end */ | ||
| 6759 | }; | ||
| 6760 | |||
| 6761 | /* | ||
| 6762 | * 6ch mode | ||
| 6763 | */ | ||
| 6764 | static struct hda_verb alc883_3ST_ch6_intel_init[] = { | ||
| 6765 | { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
| 6766 | { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
| 6767 | { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
| 6768 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
| 6769 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
| 6770 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
| 6771 | { } /* end */ | ||
| 6772 | }; | ||
| 6773 | |||
| 6774 | static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { | ||
| 6775 | { 2, alc883_3ST_ch2_intel_init }, | ||
| 6776 | { 4, alc883_3ST_ch4_intel_init }, | ||
| 6777 | { 6, alc883_3ST_ch6_intel_init }, | ||
| 6778 | }; | ||
| 6779 | |||
| 6780 | /* | ||
| 6653 | * 6ch mode | 6781 | * 6ch mode |
| 6654 | */ | 6782 | */ |
| 6655 | static struct hda_verb alc883_sixstack_ch6_init[] = { | 6783 | static struct hda_verb alc883_sixstack_ch6_init[] = { |
| @@ -6881,15 +7009,54 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { | |||
| 6881 | { } /* end */ | 7009 | { } /* end */ |
| 6882 | }; | 7010 | }; |
| 6883 | 7011 | ||
| 7012 | static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { | ||
| 7013 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
| 7014 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
| 7015 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
| 7016 | HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), | ||
| 7017 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, | ||
| 7018 | HDA_OUTPUT), | ||
| 7019 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
| 7020 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
| 7021 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
| 7022 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
| 7023 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
| 7024 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
| 7025 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
| 7026 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
| 7027 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
| 7028 | HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), | ||
| 7029 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
| 7030 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
| 7031 | HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT), | ||
| 7032 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
| 7033 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
| 7034 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
| 7035 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
| 7036 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
| 7037 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
| 7038 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
| 7039 | { | ||
| 7040 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 7041 | /* .name = "Capture Source", */ | ||
| 7042 | .name = "Input Source", | ||
| 7043 | .count = 2, | ||
| 7044 | .info = alc883_mux_enum_info, | ||
| 7045 | .get = alc883_mux_enum_get, | ||
| 7046 | .put = alc883_mux_enum_put, | ||
| 7047 | }, | ||
| 7048 | { } /* end */ | ||
| 7049 | }; | ||
| 7050 | |||
| 6884 | static struct snd_kcontrol_new alc883_fivestack_mixer[] = { | 7051 | static struct snd_kcontrol_new alc883_fivestack_mixer[] = { |
| 6885 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 7052 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
| 6886 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 7053 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
| 6887 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 7054 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
| 6888 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 7055 | HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), |
| 6889 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 7056 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
| 6890 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 7057 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
| 6891 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | 7058 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
| 6892 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 7059 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), |
| 6893 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 7060 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
| 6894 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 7061 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
| 6895 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 7062 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
| @@ -7729,6 +7896,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { | |||
| 7729 | [ALC883_MITAC] = "mitac", | 7896 | [ALC883_MITAC] = "mitac", |
| 7730 | [ALC883_CLEVO_M720] = "clevo-m720", | 7897 | [ALC883_CLEVO_M720] = "clevo-m720", |
| 7731 | [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", | 7898 | [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", |
| 7899 | [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", | ||
| 7732 | [ALC883_AUTO] = "auto", | 7900 | [ALC883_AUTO] = "auto", |
| 7733 | }; | 7901 | }; |
| 7734 | 7902 | ||
| @@ -7786,6 +7954,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { | |||
| 7786 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), | 7954 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), |
| 7787 | SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), | 7955 | SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), |
| 7788 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), | 7956 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), |
| 7957 | SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), | ||
| 7958 | SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), | ||
| 7789 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), | 7959 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), |
| 7790 | {} | 7960 | {} |
| 7791 | }; | 7961 | }; |
| @@ -7824,6 +7994,18 @@ static struct alc_config_preset alc883_presets[] = { | |||
| 7824 | .need_dac_fix = 1, | 7994 | .need_dac_fix = 1, |
| 7825 | .input_mux = &alc883_capture_source, | 7995 | .input_mux = &alc883_capture_source, |
| 7826 | }, | 7996 | }, |
| 7997 | [ALC883_3ST_6ch_INTEL] = { | ||
| 7998 | .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer }, | ||
| 7999 | .init_verbs = { alc883_init_verbs }, | ||
| 8000 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
| 8001 | .dac_nids = alc883_dac_nids, | ||
| 8002 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
| 8003 | .dig_in_nid = ALC883_DIGIN_NID, | ||
| 8004 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), | ||
| 8005 | .channel_mode = alc883_3ST_6ch_intel_modes, | ||
| 8006 | .need_dac_fix = 1, | ||
| 8007 | .input_mux = &alc883_3stack_6ch_intel, | ||
| 8008 | }, | ||
| 7827 | [ALC883_6ST_DIG] = { | 8009 | [ALC883_6ST_DIG] = { |
| 7828 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, | 8010 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, |
| 7829 | .init_verbs = { alc883_init_verbs }, | 8011 | .init_verbs = { alc883_init_verbs }, |
| @@ -8145,6 +8327,8 @@ static int patch_alc883(struct hda_codec *codec) | |||
| 8145 | 8327 | ||
| 8146 | codec->spec = spec; | 8328 | codec->spec = spec; |
| 8147 | 8329 | ||
| 8330 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); | ||
| 8331 | |||
| 8148 | board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, | 8332 | board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, |
| 8149 | alc883_models, | 8333 | alc883_models, |
| 8150 | alc883_cfg_tbl); | 8334 | alc883_cfg_tbl); |
| @@ -8171,12 +8355,25 @@ static int patch_alc883(struct hda_codec *codec) | |||
| 8171 | if (board_config != ALC883_AUTO) | 8355 | if (board_config != ALC883_AUTO) |
| 8172 | setup_preset(spec, &alc883_presets[board_config]); | 8356 | setup_preset(spec, &alc883_presets[board_config]); |
| 8173 | 8357 | ||
| 8174 | spec->stream_name_analog = "ALC883 Analog"; | 8358 | switch (codec->vendor_id) { |
| 8359 | case 0x10ec0888: | ||
| 8360 | spec->stream_name_analog = "ALC888 Analog"; | ||
| 8361 | spec->stream_name_digital = "ALC888 Digital"; | ||
| 8362 | break; | ||
| 8363 | case 0x10ec0889: | ||
| 8364 | spec->stream_name_analog = "ALC889 Analog"; | ||
| 8365 | spec->stream_name_digital = "ALC889 Digital"; | ||
| 8366 | break; | ||
| 8367 | default: | ||
| 8368 | spec->stream_name_analog = "ALC883 Analog"; | ||
| 8369 | spec->stream_name_digital = "ALC883 Digital"; | ||
| 8370 | break; | ||
| 8371 | } | ||
| 8372 | |||
| 8175 | spec->stream_analog_playback = &alc883_pcm_analog_playback; | 8373 | spec->stream_analog_playback = &alc883_pcm_analog_playback; |
| 8176 | spec->stream_analog_capture = &alc883_pcm_analog_capture; | 8374 | spec->stream_analog_capture = &alc883_pcm_analog_capture; |
| 8177 | spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; | 8375 | spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; |
| 8178 | 8376 | ||
| 8179 | spec->stream_name_digital = "ALC883 Digital"; | ||
| 8180 | spec->stream_digital_playback = &alc883_pcm_digital_playback; | 8377 | spec->stream_digital_playback = &alc883_pcm_digital_playback; |
| 8181 | spec->stream_digital_capture = &alc883_pcm_digital_capture; | 8378 | spec->stream_digital_capture = &alc883_pcm_digital_capture; |
| 8182 | 8379 | ||
| @@ -8189,6 +8386,9 @@ static int patch_alc883(struct hda_codec *codec) | |||
| 8189 | codec->patch_ops = alc_patch_ops; | 8386 | codec->patch_ops = alc_patch_ops; |
| 8190 | if (board_config == ALC883_AUTO) | 8387 | if (board_config == ALC883_AUTO) |
| 8191 | spec->init_hook = alc883_auto_init; | 8388 | spec->init_hook = alc883_auto_init; |
| 8389 | else if (codec->vendor_id == 0x10ec0888) | ||
| 8390 | spec->init_hook = alc888_coef_init; | ||
| 8391 | |||
| 8192 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 8392 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 8193 | if (!spec->loopback.amplist) | 8393 | if (!spec->loopback.amplist) |
| 8194 | spec->loopback.amplist = alc883_loopbacks; | 8394 | spec->loopback.amplist = alc883_loopbacks; |
| @@ -9522,6 +9722,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { | |||
| 9522 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 9722 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), |
| 9523 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 9723 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), |
| 9524 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), | 9724 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), |
| 9725 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", | ||
| 9726 | ALC262_SONY_ASSAMD), | ||
| 9525 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), | 9727 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), |
| 9526 | SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), | 9728 | SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), |
| 9527 | SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), | 9729 | SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), |
| @@ -9729,6 +9931,8 @@ static int patch_alc262(struct hda_codec *codec) | |||
| 9729 | } | 9931 | } |
| 9730 | #endif | 9932 | #endif |
| 9731 | 9933 | ||
| 9934 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); | ||
| 9935 | |||
| 9732 | board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, | 9936 | board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, |
| 9733 | alc262_models, | 9937 | alc262_models, |
| 9734 | alc262_cfg_tbl); | 9938 | alc262_cfg_tbl); |
| @@ -10674,12 +10878,18 @@ static int patch_alc268(struct hda_codec *codec) | |||
| 10674 | if (board_config != ALC268_AUTO) | 10878 | if (board_config != ALC268_AUTO) |
| 10675 | setup_preset(spec, &alc268_presets[board_config]); | 10879 | setup_preset(spec, &alc268_presets[board_config]); |
| 10676 | 10880 | ||
| 10677 | spec->stream_name_analog = "ALC268 Analog"; | 10881 | if (codec->vendor_id == 0x10ec0267) { |
| 10882 | spec->stream_name_analog = "ALC267 Analog"; | ||
| 10883 | spec->stream_name_digital = "ALC267 Digital"; | ||
| 10884 | } else { | ||
| 10885 | spec->stream_name_analog = "ALC268 Analog"; | ||
| 10886 | spec->stream_name_digital = "ALC268 Digital"; | ||
| 10887 | } | ||
| 10888 | |||
| 10678 | spec->stream_analog_playback = &alc268_pcm_analog_playback; | 10889 | spec->stream_analog_playback = &alc268_pcm_analog_playback; |
| 10679 | spec->stream_analog_capture = &alc268_pcm_analog_capture; | 10890 | spec->stream_analog_capture = &alc268_pcm_analog_capture; |
| 10680 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; | 10891 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; |
| 10681 | 10892 | ||
| 10682 | spec->stream_name_digital = "ALC268 Digital"; | ||
| 10683 | spec->stream_digital_playback = &alc268_pcm_digital_playback; | 10893 | spec->stream_digital_playback = &alc268_pcm_digital_playback; |
| 10684 | 10894 | ||
| 10685 | if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) | 10895 | if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) |
| @@ -11033,6 +11243,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
| 11033 | 11243 | ||
| 11034 | codec->spec = spec; | 11244 | codec->spec = spec; |
| 11035 | 11245 | ||
| 11246 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | ||
| 11247 | |||
| 11036 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, | 11248 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, |
| 11037 | alc269_models, | 11249 | alc269_models, |
| 11038 | alc269_cfg_tbl); | 11250 | alc269_cfg_tbl); |
| @@ -12631,6 +12843,12 @@ static struct hda_verb alc861vd_eapd_verbs[] = { | |||
| 12631 | { } | 12843 | { } |
| 12632 | }; | 12844 | }; |
| 12633 | 12845 | ||
| 12846 | static struct hda_verb alc660vd_eapd_verbs[] = { | ||
| 12847 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
| 12848 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
| 12849 | { } | ||
| 12850 | }; | ||
| 12851 | |||
| 12634 | static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { | 12852 | static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { |
| 12635 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 12853 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
| 12636 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 12854 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
| @@ -12786,6 +13004,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { | |||
| 12786 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), | 13004 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), |
| 12787 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), | 13005 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), |
| 12788 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), | 13006 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), |
| 13007 | SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO), | ||
| 12789 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), | 13008 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), |
| 12790 | {} | 13009 | {} |
| 12791 | }; | 13010 | }; |
| @@ -13168,11 +13387,19 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
| 13168 | if (board_config != ALC861VD_AUTO) | 13387 | if (board_config != ALC861VD_AUTO) |
| 13169 | setup_preset(spec, &alc861vd_presets[board_config]); | 13388 | setup_preset(spec, &alc861vd_presets[board_config]); |
| 13170 | 13389 | ||
| 13171 | spec->stream_name_analog = "ALC861VD Analog"; | 13390 | if (codec->vendor_id == 0x10ec0660) { |
| 13391 | spec->stream_name_analog = "ALC660-VD Analog"; | ||
| 13392 | spec->stream_name_digital = "ALC660-VD Digital"; | ||
| 13393 | /* always turn on EAPD */ | ||
| 13394 | spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs; | ||
| 13395 | } else { | ||
| 13396 | spec->stream_name_analog = "ALC861VD Analog"; | ||
| 13397 | spec->stream_name_digital = "ALC861VD Digital"; | ||
| 13398 | } | ||
| 13399 | |||
| 13172 | spec->stream_analog_playback = &alc861vd_pcm_analog_playback; | 13400 | spec->stream_analog_playback = &alc861vd_pcm_analog_playback; |
| 13173 | spec->stream_analog_capture = &alc861vd_pcm_analog_capture; | 13401 | spec->stream_analog_capture = &alc861vd_pcm_analog_capture; |
| 13174 | 13402 | ||
| 13175 | spec->stream_name_digital = "ALC861VD Digital"; | ||
| 13176 | spec->stream_digital_playback = &alc861vd_pcm_digital_playback; | 13403 | spec->stream_digital_playback = &alc861vd_pcm_digital_playback; |
| 13177 | spec->stream_digital_capture = &alc861vd_pcm_digital_capture; | 13404 | spec->stream_digital_capture = &alc861vd_pcm_digital_capture; |
| 13178 | 13405 | ||
| @@ -13251,6 +13478,23 @@ static struct hda_input_mux alc662_eeepc_capture_source = { | |||
| 13251 | }, | 13478 | }, |
| 13252 | }; | 13479 | }; |
| 13253 | 13480 | ||
| 13481 | static struct hda_input_mux alc663_capture_source = { | ||
| 13482 | .num_items = 3, | ||
| 13483 | .items = { | ||
| 13484 | { "Mic", 0x0 }, | ||
| 13485 | { "Front Mic", 0x1 }, | ||
| 13486 | { "Line", 0x2 }, | ||
| 13487 | }, | ||
| 13488 | }; | ||
| 13489 | |||
| 13490 | static struct hda_input_mux alc663_m51va_capture_source = { | ||
| 13491 | .num_items = 2, | ||
| 13492 | .items = { | ||
| 13493 | { "Ext-Mic", 0x0 }, | ||
| 13494 | { "D-Mic", 0x9 }, | ||
| 13495 | }, | ||
| 13496 | }; | ||
| 13497 | |||
| 13254 | #define alc662_mux_enum_info alc_mux_enum_info | 13498 | #define alc662_mux_enum_info alc_mux_enum_info |
| 13255 | #define alc662_mux_enum_get alc_mux_enum_get | 13499 | #define alc662_mux_enum_get alc_mux_enum_get |
| 13256 | #define alc662_mux_enum_put alc882_mux_enum_put | 13500 | #define alc662_mux_enum_put alc882_mux_enum_put |
| @@ -13431,6 +13675,44 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { | |||
| 13431 | { } /* end */ | 13675 | { } /* end */ |
| 13432 | }; | 13676 | }; |
| 13433 | 13677 | ||
| 13678 | static struct snd_kcontrol_new alc663_m51va_mixer[] = { | ||
| 13679 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
| 13680 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
| 13681 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
| 13682 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
| 13683 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
| 13684 | HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT), | ||
| 13685 | { } /* end */ | ||
| 13686 | }; | ||
| 13687 | |||
| 13688 | static struct snd_kcontrol_new alc663_g71v_mixer[] = { | ||
| 13689 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
| 13690 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
| 13691 | HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
| 13692 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
| 13693 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
| 13694 | |||
| 13695 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
| 13696 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
| 13697 | HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
| 13698 | HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
| 13699 | { } /* end */ | ||
| 13700 | }; | ||
| 13701 | |||
| 13702 | static struct snd_kcontrol_new alc663_g50v_mixer[] = { | ||
| 13703 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
| 13704 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
| 13705 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
| 13706 | |||
| 13707 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
| 13708 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
| 13709 | HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
| 13710 | HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
| 13711 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
| 13712 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
| 13713 | { } /* end */ | ||
| 13714 | }; | ||
| 13715 | |||
| 13434 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { | 13716 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { |
| 13435 | { | 13717 | { |
| 13436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13718 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| @@ -13501,6 +13783,11 @@ static struct hda_verb alc662_init_verbs[] = { | |||
| 13501 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 13783 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
| 13502 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 13784 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
| 13503 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 13785 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
| 13786 | |||
| 13787 | /* always trun on EAPD */ | ||
| 13788 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
| 13789 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
| 13790 | |||
| 13504 | { } | 13791 | { } |
| 13505 | }; | 13792 | }; |
| 13506 | 13793 | ||
| @@ -13571,6 +13858,43 @@ static struct hda_verb alc662_auto_init_verbs[] = { | |||
| 13571 | { } | 13858 | { } |
| 13572 | }; | 13859 | }; |
| 13573 | 13860 | ||
| 13861 | static struct hda_verb alc663_m51va_init_verbs[] = { | ||
| 13862 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 13863 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
| 13864 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ | ||
| 13865 | |||
| 13866 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, | ||
| 13867 | |||
| 13868 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
| 13869 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
| 13870 | {} | ||
| 13871 | }; | ||
| 13872 | |||
| 13873 | static struct hda_verb alc663_g71v_init_verbs[] = { | ||
| 13874 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 13875 | /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ | ||
| 13876 | /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ | ||
| 13877 | |||
| 13878 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 13879 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
| 13880 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ | ||
| 13881 | |||
| 13882 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, | ||
| 13883 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT}, | ||
| 13884 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, | ||
| 13885 | {} | ||
| 13886 | }; | ||
| 13887 | |||
| 13888 | static struct hda_verb alc663_g50v_init_verbs[] = { | ||
| 13889 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 13890 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
| 13891 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ | ||
| 13892 | |||
| 13893 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
| 13894 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
| 13895 | {} | ||
| 13896 | }; | ||
| 13897 | |||
| 13574 | /* capture mixer elements */ | 13898 | /* capture mixer elements */ |
| 13575 | static struct snd_kcontrol_new alc662_capture_mixer[] = { | 13899 | static struct snd_kcontrol_new alc662_capture_mixer[] = { |
| 13576 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | 13900 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), |
| @@ -13692,6 +14016,125 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) | |||
| 13692 | alc662_eeepc_ep20_automute(codec); | 14016 | alc662_eeepc_ep20_automute(codec); |
| 13693 | } | 14017 | } |
| 13694 | 14018 | ||
| 14019 | static void alc663_m51va_speaker_automute(struct hda_codec *codec) | ||
| 14020 | { | ||
| 14021 | unsigned int present; | ||
| 14022 | unsigned char bits; | ||
| 14023 | |||
| 14024 | present = snd_hda_codec_read(codec, 0x21, 0, | ||
| 14025 | AC_VERB_GET_PIN_SENSE, 0) | ||
| 14026 | & AC_PINSENSE_PRESENCE; | ||
| 14027 | bits = present ? HDA_AMP_MUTE : 0; | ||
| 14028 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
| 14029 | HDA_AMP_MUTE, bits); | ||
| 14030 | } | ||
| 14031 | |||
| 14032 | static void alc663_m51va_mic_automute(struct hda_codec *codec) | ||
| 14033 | { | ||
| 14034 | unsigned int present; | ||
| 14035 | |||
| 14036 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
| 14037 | AC_VERB_GET_PIN_SENSE, 0) | ||
| 14038 | & AC_PINSENSE_PRESENCE; | ||
| 14039 | snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
| 14040 | 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); | ||
| 14041 | snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
| 14042 | 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); | ||
| 14043 | snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
| 14044 | 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); | ||
| 14045 | snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
| 14046 | 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); | ||
| 14047 | } | ||
| 14048 | |||
| 14049 | static void alc663_m51va_unsol_event(struct hda_codec *codec, | ||
| 14050 | unsigned int res) | ||
| 14051 | { | ||
| 14052 | switch (res >> 26) { | ||
| 14053 | case ALC880_HP_EVENT: | ||
| 14054 | alc663_m51va_speaker_automute(codec); | ||
| 14055 | break; | ||
| 14056 | case ALC880_MIC_EVENT: | ||
| 14057 | alc663_m51va_mic_automute(codec); | ||
| 14058 | break; | ||
| 14059 | } | ||
| 14060 | } | ||
| 14061 | |||
| 14062 | static void alc663_m51va_inithook(struct hda_codec *codec) | ||
| 14063 | { | ||
| 14064 | alc663_m51va_speaker_automute(codec); | ||
| 14065 | alc663_m51va_mic_automute(codec); | ||
| 14066 | } | ||
| 14067 | |||
| 14068 | static void alc663_g71v_hp_automute(struct hda_codec *codec) | ||
| 14069 | { | ||
| 14070 | unsigned int present; | ||
| 14071 | unsigned char bits; | ||
| 14072 | |||
| 14073 | present = snd_hda_codec_read(codec, 0x21, 0, | ||
| 14074 | AC_VERB_GET_PIN_SENSE, 0) | ||
| 14075 | & AC_PINSENSE_PRESENCE; | ||
| 14076 | bits = present ? HDA_AMP_MUTE : 0; | ||
| 14077 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
| 14078 | HDA_AMP_MUTE, bits); | ||
| 14079 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
| 14080 | HDA_AMP_MUTE, bits); | ||
| 14081 | } | ||
| 14082 | |||
| 14083 | static void alc663_g71v_front_automute(struct hda_codec *codec) | ||
| 14084 | { | ||
| 14085 | unsigned int present; | ||
| 14086 | unsigned char bits; | ||
| 14087 | |||
| 14088 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
| 14089 | AC_VERB_GET_PIN_SENSE, 0) | ||
| 14090 | & AC_PINSENSE_PRESENCE; | ||
| 14091 | bits = present ? HDA_AMP_MUTE : 0; | ||
| 14092 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
| 14093 | HDA_AMP_MUTE, bits); | ||
| 14094 | } | ||
| 14095 | |||
| 14096 | static void alc663_g71v_unsol_event(struct hda_codec *codec, | ||
| 14097 | unsigned int res) | ||
| 14098 | { | ||
| 14099 | switch (res >> 26) { | ||
| 14100 | case ALC880_HP_EVENT: | ||
| 14101 | alc663_g71v_hp_automute(codec); | ||
| 14102 | break; | ||
| 14103 | case ALC880_FRONT_EVENT: | ||
| 14104 | alc663_g71v_front_automute(codec); | ||
| 14105 | break; | ||
| 14106 | case ALC880_MIC_EVENT: | ||
| 14107 | alc662_eeepc_mic_automute(codec); | ||
| 14108 | break; | ||
| 14109 | } | ||
| 14110 | } | ||
| 14111 | |||
| 14112 | static void alc663_g71v_inithook(struct hda_codec *codec) | ||
| 14113 | { | ||
| 14114 | alc663_g71v_front_automute(codec); | ||
| 14115 | alc663_g71v_hp_automute(codec); | ||
| 14116 | alc662_eeepc_mic_automute(codec); | ||
| 14117 | } | ||
| 14118 | |||
| 14119 | static void alc663_g50v_unsol_event(struct hda_codec *codec, | ||
| 14120 | unsigned int res) | ||
| 14121 | { | ||
| 14122 | switch (res >> 26) { | ||
| 14123 | case ALC880_HP_EVENT: | ||
| 14124 | alc663_m51va_speaker_automute(codec); | ||
| 14125 | break; | ||
| 14126 | case ALC880_MIC_EVENT: | ||
| 14127 | alc662_eeepc_mic_automute(codec); | ||
| 14128 | break; | ||
| 14129 | } | ||
| 14130 | } | ||
| 14131 | |||
| 14132 | static void alc663_g50v_inithook(struct hda_codec *codec) | ||
| 14133 | { | ||
| 14134 | alc663_m51va_speaker_automute(codec); | ||
| 14135 | alc662_eeepc_mic_automute(codec); | ||
| 14136 | } | ||
| 14137 | |||
| 13695 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 14138 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 13696 | #define alc662_loopbacks alc880_loopbacks | 14139 | #define alc662_loopbacks alc880_loopbacks |
| 13697 | #endif | 14140 | #endif |
| @@ -13714,14 +14157,24 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { | |||
| 13714 | [ALC662_LENOVO_101E] = "lenovo-101e", | 14157 | [ALC662_LENOVO_101E] = "lenovo-101e", |
| 13715 | [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", | 14158 | [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", |
| 13716 | [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", | 14159 | [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", |
| 14160 | [ALC663_ASUS_M51VA] = "m51va", | ||
| 14161 | [ALC663_ASUS_G71V] = "g71v", | ||
| 14162 | [ALC663_ASUS_H13] = "h13", | ||
| 14163 | [ALC663_ASUS_G50V] = "g50v", | ||
| 13717 | [ALC662_AUTO] = "auto", | 14164 | [ALC662_AUTO] = "auto", |
| 13718 | }; | 14165 | }; |
| 13719 | 14166 | ||
| 13720 | static struct snd_pci_quirk alc662_cfg_tbl[] = { | 14167 | static struct snd_pci_quirk alc662_cfg_tbl[] = { |
| 14168 | SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V), | ||
| 14169 | SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), | ||
| 14170 | SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V), | ||
| 13721 | SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), | 14171 | SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), |
| 13722 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), | 14172 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), |
| 13723 | SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), | 14173 | SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), |
| 13724 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | 14174 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), |
| 14175 | SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13), | ||
| 14176 | SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13), | ||
| 14177 | SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13), | ||
| 13725 | {} | 14178 | {} |
| 13726 | }; | 14179 | }; |
| 13727 | 14180 | ||
| @@ -13809,7 +14262,53 @@ static struct alc_config_preset alc662_presets[] = { | |||
| 13809 | .unsol_event = alc662_eeepc_ep20_unsol_event, | 14262 | .unsol_event = alc662_eeepc_ep20_unsol_event, |
| 13810 | .init_hook = alc662_eeepc_ep20_inithook, | 14263 | .init_hook = alc662_eeepc_ep20_inithook, |
| 13811 | }, | 14264 | }, |
| 13812 | 14265 | [ALC663_ASUS_M51VA] = { | |
| 14266 | .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, | ||
| 14267 | .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, | ||
| 14268 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
| 14269 | .dac_nids = alc662_dac_nids, | ||
| 14270 | .dig_out_nid = ALC662_DIGOUT_NID, | ||
| 14271 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
| 14272 | .channel_mode = alc662_3ST_2ch_modes, | ||
| 14273 | .input_mux = &alc663_m51va_capture_source, | ||
| 14274 | .unsol_event = alc663_m51va_unsol_event, | ||
| 14275 | .init_hook = alc663_m51va_inithook, | ||
| 14276 | }, | ||
| 14277 | [ALC663_ASUS_G71V] = { | ||
| 14278 | .mixers = { alc663_g71v_mixer, alc662_capture_mixer}, | ||
| 14279 | .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, | ||
| 14280 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
| 14281 | .dac_nids = alc662_dac_nids, | ||
| 14282 | .dig_out_nid = ALC662_DIGOUT_NID, | ||
| 14283 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
| 14284 | .channel_mode = alc662_3ST_2ch_modes, | ||
| 14285 | .input_mux = &alc662_eeepc_capture_source, | ||
| 14286 | .unsol_event = alc663_g71v_unsol_event, | ||
| 14287 | .init_hook = alc663_g71v_inithook, | ||
| 14288 | }, | ||
| 14289 | [ALC663_ASUS_H13] = { | ||
| 14290 | .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, | ||
| 14291 | .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, | ||
| 14292 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
| 14293 | .dac_nids = alc662_dac_nids, | ||
| 14294 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
| 14295 | .channel_mode = alc662_3ST_2ch_modes, | ||
| 14296 | .input_mux = &alc663_m51va_capture_source, | ||
| 14297 | .unsol_event = alc663_m51va_unsol_event, | ||
| 14298 | .init_hook = alc663_m51va_inithook, | ||
| 14299 | }, | ||
| 14300 | [ALC663_ASUS_G50V] = { | ||
| 14301 | .mixers = { alc663_g50v_mixer, alc662_capture_mixer}, | ||
| 14302 | .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, | ||
| 14303 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
| 14304 | .dac_nids = alc662_dac_nids, | ||
| 14305 | .dig_out_nid = ALC662_DIGOUT_NID, | ||
| 14306 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), | ||
| 14307 | .channel_mode = alc662_3ST_6ch_modes, | ||
| 14308 | .input_mux = &alc663_capture_source, | ||
| 14309 | .unsol_event = alc663_g50v_unsol_event, | ||
| 14310 | .init_hook = alc663_g50v_inithook, | ||
| 14311 | }, | ||
| 13813 | }; | 14312 | }; |
| 13814 | 14313 | ||
| 13815 | 14314 | ||
| @@ -14082,6 +14581,8 @@ static int patch_alc662(struct hda_codec *codec) | |||
| 14082 | 14581 | ||
| 14083 | codec->spec = spec; | 14582 | codec->spec = spec; |
| 14084 | 14583 | ||
| 14584 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | ||
| 14585 | |||
| 14085 | board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, | 14586 | board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, |
| 14086 | alc662_models, | 14587 | alc662_models, |
| 14087 | alc662_cfg_tbl); | 14588 | alc662_cfg_tbl); |
| @@ -14108,11 +14609,17 @@ static int patch_alc662(struct hda_codec *codec) | |||
| 14108 | if (board_config != ALC662_AUTO) | 14609 | if (board_config != ALC662_AUTO) |
| 14109 | setup_preset(spec, &alc662_presets[board_config]); | 14610 | setup_preset(spec, &alc662_presets[board_config]); |
| 14110 | 14611 | ||
| 14111 | spec->stream_name_analog = "ALC662 Analog"; | 14612 | if (codec->vendor_id == 0x10ec0663) { |
| 14613 | spec->stream_name_analog = "ALC663 Analog"; | ||
| 14614 | spec->stream_name_digital = "ALC663 Digital"; | ||
| 14615 | } else { | ||
| 14616 | spec->stream_name_analog = "ALC662 Analog"; | ||
| 14617 | spec->stream_name_digital = "ALC662 Digital"; | ||
| 14618 | } | ||
| 14619 | |||
| 14112 | spec->stream_analog_playback = &alc662_pcm_analog_playback; | 14620 | spec->stream_analog_playback = &alc662_pcm_analog_playback; |
| 14113 | spec->stream_analog_capture = &alc662_pcm_analog_capture; | 14621 | spec->stream_analog_capture = &alc662_pcm_analog_capture; |
| 14114 | 14622 | ||
| 14115 | spec->stream_name_digital = "ALC662 Digital"; | ||
| 14116 | spec->stream_digital_playback = &alc662_pcm_digital_playback; | 14623 | spec->stream_digital_playback = &alc662_pcm_digital_playback; |
| 14117 | spec->stream_digital_capture = &alc662_pcm_digital_capture; | 14624 | spec->stream_digital_capture = &alc662_pcm_digital_capture; |
| 14118 | 14625 | ||
| @@ -14151,6 +14658,7 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
| 14151 | .patch = patch_alc883 }, | 14658 | .patch = patch_alc883 }, |
| 14152 | { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", | 14659 | { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", |
| 14153 | .patch = patch_alc662 }, | 14660 | .patch = patch_alc662 }, |
| 14661 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, | ||
| 14154 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | 14662 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, |
| 14155 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | 14663 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, |
| 14156 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, | 14664 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a4f44a00bae8..08cb77f51880 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
| @@ -636,21 +636,28 @@ static struct hda_verb stac92hd71bxx_core_init[] = { | |||
| 636 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 636 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
| 637 | }; | 637 | }; |
| 638 | 638 | ||
| 639 | #define HD_DISABLE_PORTF 3 | ||
| 639 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { | 640 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { |
| 641 | /* start of config #1 */ | ||
| 642 | |||
| 643 | /* connect port 0f to audio mixer */ | ||
| 644 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
| 645 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
| 646 | /* unmute right and left channels for node 0x0f */ | ||
| 647 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
| 648 | /* start of config #2 */ | ||
| 649 | |||
| 640 | /* set master volume and direct control */ | 650 | /* set master volume and direct control */ |
| 641 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 651 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
| 642 | /* connect headphone jack to dac1 */ | 652 | /* connect headphone jack to dac1 */ |
| 643 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | 653 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, |
| 644 | /* connect ports 0d and 0f to audio mixer */ | 654 | /* connect port 0d to audio mixer */ |
| 645 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, | 655 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, |
| 646 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
| 647 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
| 648 | /* unmute dac0 input in audio mixer */ | 656 | /* unmute dac0 input in audio mixer */ |
| 649 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, | 657 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, |
| 650 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | 658 | /* unmute right and left channels for nodes 0x0a, 0xd */ |
| 651 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 659 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
| 652 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 660 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
| 653 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
| 654 | {} | 661 | {} |
| 655 | }; | 662 | }; |
| 656 | 663 | ||
| @@ -818,6 +825,9 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { | |||
| 818 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), | 825 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), |
| 819 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), | 826 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), |
| 820 | 827 | ||
| 828 | HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT), | ||
| 829 | HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), | ||
| 830 | |||
| 821 | HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), | 831 | HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), |
| 822 | HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), | 832 | HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), |
| 823 | { } /* end */ | 833 | { } /* end */ |
| @@ -1317,13 +1327,13 @@ static unsigned int ref92hd71bxx_pin_configs[10] = { | |||
| 1317 | 0x90a000f0, 0x01452050, | 1327 | 0x90a000f0, 0x01452050, |
| 1318 | }; | 1328 | }; |
| 1319 | 1329 | ||
| 1320 | static unsigned int dell_m4_1_pin_configs[13] = { | 1330 | static unsigned int dell_m4_1_pin_configs[10] = { |
| 1321 | 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, | 1331 | 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, |
| 1322 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, | 1332 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, |
| 1323 | 0x40f000f0, 0x4f0000f0, | 1333 | 0x40f000f0, 0x4f0000f0, |
| 1324 | }; | 1334 | }; |
| 1325 | 1335 | ||
| 1326 | static unsigned int dell_m4_2_pin_configs[13] = { | 1336 | static unsigned int dell_m4_2_pin_configs[10] = { |
| 1327 | 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, | 1337 | 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, |
| 1328 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, | 1338 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, |
| 1329 | 0x40f000f0, 0x044413b0, | 1339 | 0x40f000f0, 0x044413b0, |
| @@ -1754,12 +1764,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { | |||
| 1754 | "unknown Dell", STAC_9205_DELL_M42), | 1764 | "unknown Dell", STAC_9205_DELL_M42), |
| 1755 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, | 1765 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, |
| 1756 | "Dell Precision", STAC_9205_DELL_M43), | 1766 | "Dell Precision", STAC_9205_DELL_M43), |
| 1757 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, | ||
| 1758 | "Dell Precision", STAC_9205_DELL_M43), | ||
| 1759 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, | 1767 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, |
| 1760 | "Dell Precision", STAC_9205_DELL_M43), | 1768 | "Dell Precision", STAC_9205_DELL_M43), |
| 1761 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, | ||
| 1762 | "Dell Precision", STAC_9205_DELL_M43), | ||
| 1763 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, | 1769 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, |
| 1764 | "Dell Precision", STAC_9205_DELL_M43), | 1770 | "Dell Precision", STAC_9205_DELL_M43), |
| 1765 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, | 1771 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, |
| @@ -1770,18 +1776,14 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { | |||
| 1770 | "Dell Precision", STAC_9205_DELL_M43), | 1776 | "Dell Precision", STAC_9205_DELL_M43), |
| 1771 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, | 1777 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, |
| 1772 | "Dell Precision M4300", STAC_9205_DELL_M43), | 1778 | "Dell Precision M4300", STAC_9205_DELL_M43), |
| 1773 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, | ||
| 1774 | "Dell Precision", STAC_9205_DELL_M43), | ||
| 1775 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, | ||
| 1776 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
| 1777 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, | ||
| 1778 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
| 1779 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, | ||
| 1780 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
| 1781 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, | ||
| 1782 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
| 1783 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, | 1779 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, |
| 1784 | "unknown Dell", STAC_9205_DELL_M42), | 1780 | "unknown Dell", STAC_9205_DELL_M42), |
| 1781 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, | ||
| 1782 | "Dell Precision", STAC_9205_DELL_M43), | ||
| 1783 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, | ||
| 1784 | "Dell Precision", STAC_9205_DELL_M43), | ||
| 1785 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, | ||
| 1786 | "Dell Precision", STAC_9205_DELL_M43), | ||
| 1785 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, | 1787 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, |
| 1786 | "Dell Inspiron", STAC_9205_DELL_M44), | 1788 | "Dell Inspiron", STAC_9205_DELL_M44), |
| 1787 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, | 1789 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, |
| @@ -3103,13 +3105,16 @@ static int stac92xx_init(struct hda_codec *codec) | |||
| 3103 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 3105 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
| 3104 | int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i], | 3106 | int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i], |
| 3105 | 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | 3107 | 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
| 3108 | def_conf = get_defcfg_connect(def_conf); | ||
| 3106 | /* outputs are only ports capable of power management | 3109 | /* outputs are only ports capable of power management |
| 3107 | * any attempts on powering down a input port cause the | 3110 | * any attempts on powering down a input port cause the |
| 3108 | * referenced VREF to act quirky. | 3111 | * referenced VREF to act quirky. |
| 3109 | */ | 3112 | */ |
| 3110 | if (pinctl & AC_PINCTL_IN_EN) | 3113 | if (pinctl & AC_PINCTL_IN_EN) |
| 3111 | continue; | 3114 | continue; |
| 3112 | if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) | 3115 | /* skip any ports that don't have jacks since presence |
| 3116 | * detection is useless */ | ||
| 3117 | if (def_conf && def_conf != AC_JACK_PORT_FIXED) | ||
| 3113 | continue; | 3118 | continue; |
| 3114 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); | 3119 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); |
| 3115 | codec->patch_ops.unsol_event(codec, (event | i) << 26); | 3120 | codec->patch_ops.unsol_event(codec, (event | i) << 26); |
| @@ -3614,6 +3619,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) | |||
| 3614 | 3619 | ||
| 3615 | codec->spec = spec; | 3620 | codec->spec = spec; |
| 3616 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); | 3621 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); |
| 3622 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | ||
| 3617 | spec->pin_nids = stac92hd71bxx_pin_nids; | 3623 | spec->pin_nids = stac92hd71bxx_pin_nids; |
| 3618 | spec->board_config = snd_hda_check_board_config(codec, | 3624 | spec->board_config = snd_hda_check_board_config(codec, |
| 3619 | STAC_92HD71BXX_MODELS, | 3625 | STAC_92HD71BXX_MODELS, |
| @@ -3642,6 +3648,19 @@ again: | |||
| 3642 | spec->mixer = stac92hd71bxx_mixer; | 3648 | spec->mixer = stac92hd71bxx_mixer; |
| 3643 | spec->init = stac92hd71bxx_core_init; | 3649 | spec->init = stac92hd71bxx_core_init; |
| 3644 | break; | 3650 | break; |
| 3651 | case 0x111d7608: /* 5 Port with Analog Mixer */ | ||
| 3652 | /* no output amps */ | ||
| 3653 | spec->num_pwrs = 0; | ||
| 3654 | spec->mixer = stac92hd71bxx_analog_mixer; | ||
| 3655 | |||
| 3656 | /* disable VSW */ | ||
| 3657 | spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; | ||
| 3658 | stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); | ||
| 3659 | break; | ||
| 3660 | case 0x111d7603: /* 6 Port with Analog Mixer */ | ||
| 3661 | /* no output amps */ | ||
| 3662 | spec->num_pwrs = 0; | ||
| 3663 | /* fallthru */ | ||
| 3645 | default: | 3664 | default: |
| 3646 | spec->mixer = stac92hd71bxx_analog_mixer; | 3665 | spec->mixer = stac92hd71bxx_analog_mixer; |
| 3647 | spec->init = stac92hd71bxx_analog_core_init; | 3666 | spec->init = stac92hd71bxx_analog_core_init; |
| @@ -3653,22 +3672,19 @@ again: | |||
| 3653 | /* GPIO0 High = EAPD */ | 3672 | /* GPIO0 High = EAPD */ |
| 3654 | spec->gpio_mask = 0x01; | 3673 | spec->gpio_mask = 0x01; |
| 3655 | spec->gpio_dir = 0x01; | 3674 | spec->gpio_dir = 0x01; |
| 3656 | spec->gpio_mask = 0x01; | ||
| 3657 | spec->gpio_data = 0x01; | 3675 | spec->gpio_data = 0x01; |
| 3658 | 3676 | ||
| 3659 | spec->mux_nids = stac92hd71bxx_mux_nids; | 3677 | spec->mux_nids = stac92hd71bxx_mux_nids; |
| 3660 | spec->adc_nids = stac92hd71bxx_adc_nids; | 3678 | spec->adc_nids = stac92hd71bxx_adc_nids; |
| 3661 | spec->dmic_nids = stac92hd71bxx_dmic_nids; | 3679 | spec->dmic_nids = stac92hd71bxx_dmic_nids; |
| 3662 | spec->dmux_nids = stac92hd71bxx_dmux_nids; | 3680 | spec->dmux_nids = stac92hd71bxx_dmux_nids; |
| 3681 | spec->pwr_nids = stac92hd71bxx_pwr_nids; | ||
| 3663 | 3682 | ||
| 3664 | spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); | 3683 | spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); |
| 3665 | spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); | 3684 | spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); |
| 3666 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; | 3685 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; |
| 3667 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); | 3686 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); |
| 3668 | 3687 | ||
| 3669 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | ||
| 3670 | spec->pwr_nids = stac92hd71bxx_pwr_nids; | ||
| 3671 | |||
| 3672 | spec->multiout.num_dacs = 1; | 3688 | spec->multiout.num_dacs = 1; |
| 3673 | spec->multiout.hp_nid = 0x11; | 3689 | spec->multiout.hp_nid = 0x11; |
| 3674 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; | 3690 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; |
| @@ -4306,10 +4322,11 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
| 4306 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, | 4322 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, |
| 4307 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, | 4323 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, |
| 4308 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, | 4324 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, |
| 4325 | { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, | ||
| 4326 | { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, | ||
| 4309 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, | 4327 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, |
| 4310 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, | 4328 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, |
| 4311 | { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, | 4329 | { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, |
| 4312 | { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx }, | ||
| 4313 | { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | 4330 | { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, |
| 4314 | { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | 4331 | { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, |
| 4315 | { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, | 4332 | { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, |
diff --git a/sound/pci/ice1712/envy24ht.h b/sound/pci/ice1712/envy24ht.h index 43b9e3e858be..a0c5e009bb4a 100644 --- a/sound/pci/ice1712/envy24ht.h +++ b/sound/pci/ice1712/envy24ht.h | |||
| @@ -93,9 +93,13 @@ enum { | |||
| 93 | #define VT1724_REG_MPU_TXFIFO 0x0a /*byte ro. number of bytes in TX fifo*/ | 93 | #define VT1724_REG_MPU_TXFIFO 0x0a /*byte ro. number of bytes in TX fifo*/ |
| 94 | #define VT1724_REG_MPU_RXFIFO 0x0b /*byte ro. number of bytes in RX fifo*/ | 94 | #define VT1724_REG_MPU_RXFIFO 0x0b /*byte ro. number of bytes in RX fifo*/ |
| 95 | 95 | ||
| 96 | //are these 2 the wrong way around? they don't seem to be used yet anyway | 96 | #define VT1724_REG_MPU_DATA 0x0c /* byte */ |
| 97 | #define VT1724_REG_MPU_CTRL 0x0c /* byte */ | 97 | #define VT1724_REG_MPU_CTRL 0x0d /* byte */ |
| 98 | #define VT1724_REG_MPU_DATA 0x0d /* byte */ | 98 | #define VT1724_MPU_UART 0x01 |
| 99 | #define VT1724_MPU_TX_EMPTY 0x02 | ||
| 100 | #define VT1724_MPU_TX_FULL 0x04 | ||
| 101 | #define VT1724_MPU_RX_EMPTY 0x08 | ||
| 102 | #define VT1724_MPU_RX_FULL 0x10 | ||
| 99 | 103 | ||
| 100 | #define VT1724_REG_MPU_FIFO_WM 0x0e /*byte set the high/low watermarks for RX/TX fifos*/ | 104 | #define VT1724_REG_MPU_FIFO_WM 0x0e /*byte set the high/low watermarks for RX/TX fifos*/ |
| 101 | #define VT1724_MPU_RX_FIFO 0x20 //1=rx fifo watermark 0=tx fifo watermark | 105 | #define VT1724_MPU_RX_FIFO 0x20 //1=rx fifo watermark 0=tx fifo watermark |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 3208901c740e..762fbd7a7507 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
| @@ -333,6 +333,8 @@ struct snd_ice1712 { | |||
| 333 | unsigned int has_spdif: 1; /* VT1720/4 - has SPDIF I/O */ | 333 | unsigned int has_spdif: 1; /* VT1720/4 - has SPDIF I/O */ |
| 334 | unsigned int force_pdma4: 1; /* VT1720/4 - PDMA4 as non-spdif */ | 334 | unsigned int force_pdma4: 1; /* VT1720/4 - PDMA4 as non-spdif */ |
| 335 | unsigned int force_rdma1: 1; /* VT1720/4 - RDMA1 as non-spdif */ | 335 | unsigned int force_rdma1: 1; /* VT1720/4 - RDMA1 as non-spdif */ |
| 336 | unsigned int midi_output: 1; /* VT1720/4: MIDI output triggered */ | ||
| 337 | unsigned int midi_input: 1; /* VT1720/4: MIDI input triggered */ | ||
| 336 | unsigned int num_total_dacs; /* total DACs */ | 338 | unsigned int num_total_dacs; /* total DACs */ |
| 337 | unsigned int num_total_adcs; /* total ADCs */ | 339 | unsigned int num_total_adcs; /* total ADCs */ |
| 338 | unsigned int cur_rate; /* current rate */ | 340 | unsigned int cur_rate; /* current rate */ |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 67350901772c..e596d777d9dd 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
| 33 | #include <sound/core.h> | 33 | #include <sound/core.h> |
| 34 | #include <sound/info.h> | 34 | #include <sound/info.h> |
| 35 | #include <sound/mpu401.h> | 35 | #include <sound/rawmidi.h> |
| 36 | #include <sound/initval.h> | 36 | #include <sound/initval.h> |
| 37 | 37 | ||
| 38 | #include <sound/asoundef.h> | 38 | #include <sound/asoundef.h> |
| @@ -223,30 +223,153 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice) | |||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | /* | 225 | /* |
| 226 | * MPU401 accessor | 226 | * MIDI |
| 227 | */ | 227 | */ |
| 228 | static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu, | 228 | |
| 229 | unsigned long addr) | 229 | static void vt1724_midi_clear_rx(struct snd_ice1712 *ice) |
| 230 | { | ||
| 231 | unsigned int count; | ||
| 232 | |||
| 233 | for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count) | ||
| 234 | inb(ICEREG1724(ice, MPU_DATA)); | ||
| 235 | } | ||
| 236 | |||
| 237 | static inline struct snd_rawmidi_substream * | ||
| 238 | get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream) | ||
| 230 | { | 239 | { |
| 231 | /* fix status bits to the standard position */ | 240 | return list_first_entry(&ice->rmidi[0]->streams[stream].substreams, |
| 232 | /* only RX_EMPTY and TX_FULL are checked */ | 241 | struct snd_rawmidi_substream, list); |
| 233 | if (addr == MPU401C(mpu)) | 242 | } |
| 234 | return (inb(addr) & 0x0c) << 4; | 243 | |
| 244 | static void vt1724_midi_write(struct snd_ice1712 *ice) | ||
| 245 | { | ||
| 246 | struct snd_rawmidi_substream *s; | ||
| 247 | int count, i; | ||
| 248 | u8 buffer[32]; | ||
| 249 | |||
| 250 | s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT); | ||
| 251 | count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO)); | ||
| 252 | if (count > 0) { | ||
| 253 | count = snd_rawmidi_transmit(s, buffer, count); | ||
| 254 | for (i = 0; i < count; ++i) | ||
| 255 | outb(buffer[i], ICEREG1724(ice, MPU_DATA)); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | static void vt1724_midi_read(struct snd_ice1712 *ice) | ||
| 260 | { | ||
| 261 | struct snd_rawmidi_substream *s; | ||
| 262 | int count, i; | ||
| 263 | u8 buffer[32]; | ||
| 264 | |||
| 265 | s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT); | ||
| 266 | count = inb(ICEREG1724(ice, MPU_RXFIFO)); | ||
| 267 | if (count > 0) { | ||
| 268 | count = min(count, 32); | ||
| 269 | for (i = 0; i < count; ++i) | ||
| 270 | buffer[i] = inb(ICEREG1724(ice, MPU_DATA)); | ||
| 271 | snd_rawmidi_receive(s, buffer, count); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, | ||
| 276 | u8 flag, int enable) | ||
| 277 | { | ||
| 278 | struct snd_ice1712 *ice = substream->rmidi->private_data; | ||
| 279 | u8 mask; | ||
| 280 | |||
| 281 | spin_lock_irq(&ice->reg_lock); | ||
| 282 | mask = inb(ICEREG1724(ice, IRQMASK)); | ||
| 283 | if (enable) | ||
| 284 | mask &= ~flag; | ||
| 235 | else | 285 | else |
| 236 | return inb(addr); | 286 | mask |= flag; |
| 287 | outb(mask, ICEREG1724(ice, IRQMASK)); | ||
| 288 | spin_unlock_irq(&ice->reg_lock); | ||
| 237 | } | 289 | } |
| 238 | 290 | ||
| 239 | static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu, | 291 | static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) |
| 240 | unsigned char data, unsigned long addr) | ||
| 241 | { | 292 | { |
| 242 | if (addr == MPU401C(mpu)) { | 293 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1); |
| 243 | if (data == MPU401_ENTER_UART) | 294 | return 0; |
| 244 | outb(0x01, addr); | 295 | } |
| 245 | /* what else? */ | 296 | |
| 246 | } else | 297 | static int vt1724_midi_output_close(struct snd_rawmidi_substream *s) |
| 247 | outb(data, addr); | 298 | { |
| 299 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0); | ||
| 300 | return 0; | ||
| 248 | } | 301 | } |
| 249 | 302 | ||
| 303 | static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) | ||
| 304 | { | ||
| 305 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
| 306 | unsigned long flags; | ||
| 307 | |||
| 308 | spin_lock_irqsave(&ice->reg_lock, flags); | ||
| 309 | if (up) { | ||
| 310 | ice->midi_output = 1; | ||
| 311 | vt1724_midi_write(ice); | ||
| 312 | } else { | ||
| 313 | ice->midi_output = 0; | ||
| 314 | } | ||
| 315 | spin_unlock_irqrestore(&ice->reg_lock, flags); | ||
| 316 | } | ||
| 317 | |||
| 318 | static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) | ||
| 319 | { | ||
| 320 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
| 321 | unsigned long timeout; | ||
| 322 | |||
| 323 | /* 32 bytes should be transmitted in less than about 12 ms */ | ||
| 324 | timeout = jiffies + msecs_to_jiffies(15); | ||
| 325 | do { | ||
| 326 | if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY) | ||
| 327 | break; | ||
| 328 | schedule_timeout_uninterruptible(1); | ||
| 329 | } while (time_after(timeout, jiffies)); | ||
| 330 | } | ||
| 331 | |||
| 332 | static struct snd_rawmidi_ops vt1724_midi_output_ops = { | ||
| 333 | .open = vt1724_midi_output_open, | ||
| 334 | .close = vt1724_midi_output_close, | ||
| 335 | .trigger = vt1724_midi_output_trigger, | ||
| 336 | .drain = vt1724_midi_output_drain, | ||
| 337 | }; | ||
| 338 | |||
| 339 | static int vt1724_midi_input_open(struct snd_rawmidi_substream *s) | ||
| 340 | { | ||
| 341 | vt1724_midi_clear_rx(s->rmidi->private_data); | ||
| 342 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1); | ||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int vt1724_midi_input_close(struct snd_rawmidi_substream *s) | ||
| 347 | { | ||
| 348 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0); | ||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) | ||
| 353 | { | ||
| 354 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
| 355 | unsigned long flags; | ||
| 356 | |||
| 357 | spin_lock_irqsave(&ice->reg_lock, flags); | ||
| 358 | if (up) { | ||
| 359 | ice->midi_input = 1; | ||
| 360 | vt1724_midi_read(ice); | ||
| 361 | } else { | ||
| 362 | ice->midi_input = 0; | ||
| 363 | } | ||
| 364 | spin_unlock_irqrestore(&ice->reg_lock, flags); | ||
| 365 | } | ||
| 366 | |||
| 367 | static struct snd_rawmidi_ops vt1724_midi_input_ops = { | ||
| 368 | .open = vt1724_midi_input_open, | ||
| 369 | .close = vt1724_midi_input_close, | ||
| 370 | .trigger = vt1724_midi_input_trigger, | ||
| 371 | }; | ||
| 372 | |||
| 250 | 373 | ||
| 251 | /* | 374 | /* |
| 252 | * Interrupt handler | 375 | * Interrupt handler |
| @@ -278,13 +401,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
| 278 | #endif | 401 | #endif |
| 279 | handled = 1; | 402 | handled = 1; |
| 280 | if (status & VT1724_IRQ_MPU_TX) { | 403 | if (status & VT1724_IRQ_MPU_TX) { |
| 281 | if (ice->rmidi[0]) | 404 | spin_lock(&ice->reg_lock); |
| 282 | snd_mpu401_uart_interrupt_tx(irq, | 405 | if (ice->midi_output) |
| 283 | ice->rmidi[0]->private_data); | 406 | vt1724_midi_write(ice); |
| 284 | else /* disable TX to be sure */ | 407 | spin_unlock(&ice->reg_lock); |
| 285 | outb(inb(ICEREG1724(ice, IRQMASK)) | | ||
| 286 | VT1724_IRQ_MPU_TX, | ||
| 287 | ICEREG1724(ice, IRQMASK)); | ||
| 288 | /* Due to mysterical reasons, MPU_TX is always | 408 | /* Due to mysterical reasons, MPU_TX is always |
| 289 | * generated (and can't be cleared) when a PCM | 409 | * generated (and can't be cleared) when a PCM |
| 290 | * playback is going. So let's ignore at the | 410 | * playback is going. So let's ignore at the |
| @@ -293,13 +413,12 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
| 293 | status_mask &= ~VT1724_IRQ_MPU_TX; | 413 | status_mask &= ~VT1724_IRQ_MPU_TX; |
| 294 | } | 414 | } |
| 295 | if (status & VT1724_IRQ_MPU_RX) { | 415 | if (status & VT1724_IRQ_MPU_RX) { |
| 296 | if (ice->rmidi[0]) | 416 | spin_lock(&ice->reg_lock); |
| 297 | snd_mpu401_uart_interrupt(irq, | 417 | if (ice->midi_input) |
| 298 | ice->rmidi[0]->private_data); | 418 | vt1724_midi_read(ice); |
| 299 | else /* disable RX to be sure */ | 419 | else |
| 300 | outb(inb(ICEREG1724(ice, IRQMASK)) | | 420 | vt1724_midi_clear_rx(ice); |
| 301 | VT1724_IRQ_MPU_RX, | 421 | spin_unlock(&ice->reg_lock); |
| 302 | ICEREG1724(ice, IRQMASK)); | ||
| 303 | } | 422 | } |
| 304 | /* ack MPU irq */ | 423 | /* ack MPU irq */ |
| 305 | outb(status, ICEREG1724(ice, IRQSTAT)); | 424 | outb(status, ICEREG1724(ice, IRQSTAT)); |
| @@ -2425,28 +2544,30 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, | |||
| 2425 | 2544 | ||
| 2426 | if (! c->no_mpu401) { | 2545 | if (! c->no_mpu401) { |
| 2427 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { | 2546 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { |
| 2428 | struct snd_mpu401 *mpu; | 2547 | struct snd_rawmidi *rmidi; |
| 2429 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, | 2548 | |
| 2430 | ICEREG1724(ice, MPU_CTRL), | 2549 | err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi); |
| 2431 | (MPU401_INFO_INTEGRATED | | 2550 | if (err < 0) { |
| 2432 | MPU401_INFO_NO_ACK | | ||
| 2433 | MPU401_INFO_TX_IRQ), | ||
| 2434 | ice->irq, 0, | ||
| 2435 | &ice->rmidi[0])) < 0) { | ||
| 2436 | snd_card_free(card); | 2551 | snd_card_free(card); |
| 2437 | return err; | 2552 | return err; |
| 2438 | } | 2553 | } |
| 2439 | mpu = ice->rmidi[0]->private_data; | 2554 | ice->rmidi[0] = rmidi; |
| 2440 | mpu->read = snd_vt1724_mpu401_read; | 2555 | rmidi->private_data = ice; |
| 2441 | mpu->write = snd_vt1724_mpu401_write; | 2556 | strcpy(rmidi->name, "ICE1724 MIDI"); |
| 2442 | /* unmask MPU RX/TX irqs */ | 2557 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | |
| 2443 | outb(inb(ICEREG1724(ice, IRQMASK)) & | 2558 | SNDRV_RAWMIDI_INFO_INPUT | |
| 2444 | ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX), | 2559 | SNDRV_RAWMIDI_INFO_DUPLEX; |
| 2445 | ICEREG1724(ice, IRQMASK)); | 2560 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, |
| 2561 | &vt1724_midi_output_ops); | ||
| 2562 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
| 2563 | &vt1724_midi_input_ops); | ||
| 2564 | |||
| 2446 | /* set watermarks */ | 2565 | /* set watermarks */ |
| 2447 | outb(VT1724_MPU_RX_FIFO | 0x1, | 2566 | outb(VT1724_MPU_RX_FIFO | 0x1, |
| 2448 | ICEREG1724(ice, MPU_FIFO_WM)); | 2567 | ICEREG1724(ice, MPU_FIFO_WM)); |
| 2449 | outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); | 2568 | outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); |
| 2569 | /* set UART mode */ | ||
| 2570 | outb(VT1724_MPU_UART, ICEREG1724(ice, MPU_CTRL)); | ||
| 2450 | } | 2571 | } |
| 2451 | } | 2572 | } |
| 2452 | 2573 | ||
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index a536c59fbea1..f4788dee05c3 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
| @@ -2427,6 +2427,29 @@ snd_m3_amp_enable(struct snd_m3 *chip, int enable) | |||
| 2427 | outw(0xffff, io + GPIO_MASK); | 2427 | outw(0xffff, io + GPIO_MASK); |
| 2428 | } | 2428 | } |
| 2429 | 2429 | ||
| 2430 | static void | ||
| 2431 | snd_m3_hv_init(struct snd_m3 *chip) | ||
| 2432 | { | ||
| 2433 | unsigned long io = chip->iobase; | ||
| 2434 | u16 val = GPI_VOL_DOWN | GPI_VOL_UP; | ||
| 2435 | |||
| 2436 | if (!chip->is_omnibook) | ||
| 2437 | return; | ||
| 2438 | |||
| 2439 | /* | ||
| 2440 | * Volume buttons on some HP OmniBook laptops | ||
| 2441 | * require some GPIO magic to work correctly. | ||
| 2442 | */ | ||
| 2443 | outw(0xffff, io + GPIO_MASK); | ||
| 2444 | outw(0x0000, io + GPIO_DATA); | ||
| 2445 | |||
| 2446 | outw(~val, io + GPIO_MASK); | ||
| 2447 | outw(inw(io + GPIO_DIRECTION) & ~val, io + GPIO_DIRECTION); | ||
| 2448 | outw(val, io + GPIO_MASK); | ||
| 2449 | |||
| 2450 | outw(0xffff, io + GPIO_MASK); | ||
| 2451 | } | ||
| 2452 | |||
| 2430 | static int | 2453 | static int |
| 2431 | snd_m3_chip_init(struct snd_m3 *chip) | 2454 | snd_m3_chip_init(struct snd_m3 *chip) |
| 2432 | { | 2455 | { |
| @@ -2442,21 +2465,6 @@ snd_m3_chip_init(struct snd_m3 *chip) | |||
| 2442 | DISABLE_LEGACY); | 2465 | DISABLE_LEGACY); |
| 2443 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); | 2466 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); |
| 2444 | 2467 | ||
| 2445 | if (chip->is_omnibook) { | ||
| 2446 | /* | ||
| 2447 | * Volume buttons on some HP OmniBook laptops don't work | ||
| 2448 | * correctly. This makes them work for the most part. | ||
| 2449 | * | ||
| 2450 | * Volume up and down buttons on the laptop side work. | ||
| 2451 | * Fn+cursor_up (volme up) works. | ||
| 2452 | * Fn+cursor_down (volume down) doesn't work. | ||
| 2453 | * Fn+F7 (mute) works acts as volume up. | ||
| 2454 | */ | ||
| 2455 | outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); | ||
| 2456 | outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); | ||
| 2457 | outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); | ||
| 2458 | outw(0xffff, io + GPIO_MASK); | ||
| 2459 | } | ||
| 2460 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); | 2468 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); |
| 2461 | n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); | 2469 | n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); |
| 2462 | n |= chip->hv_config; | 2470 | n |= chip->hv_config; |
| @@ -2642,6 +2650,8 @@ static int m3_resume(struct pci_dev *pci) | |||
| 2642 | snd_m3_enable_ints(chip); | 2650 | snd_m3_enable_ints(chip); |
| 2643 | snd_m3_amp_enable(chip, 1); | 2651 | snd_m3_amp_enable(chip, 1); |
| 2644 | 2652 | ||
| 2653 | snd_m3_hv_init(chip); | ||
| 2654 | |||
| 2645 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2655 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
| 2646 | return 0; | 2656 | return 0; |
| 2647 | } | 2657 | } |
| @@ -2781,6 +2791,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
| 2781 | 2791 | ||
| 2782 | snd_m3_amp_enable(chip, 1); | 2792 | snd_m3_amp_enable(chip, 1); |
| 2783 | 2793 | ||
| 2794 | snd_m3_hv_init(chip); | ||
| 2795 | |||
| 2784 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); | 2796 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); |
| 2785 | 2797 | ||
| 2786 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, | 2798 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, |
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 7efb838d18a6..06d13e717114 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
| @@ -1302,8 +1302,8 @@ snd_nm256_mixer(struct nm256 *chip) | |||
| 1302 | .read = snd_nm256_ac97_read, | 1302 | .read = snd_nm256_ac97_read, |
| 1303 | }; | 1303 | }; |
| 1304 | 1304 | ||
| 1305 | chip->ac97_regs = kcalloc(sizeof(short), | 1305 | chip->ac97_regs = kcalloc(ARRAY_SIZE(nm256_ac97_init_val), |
| 1306 | ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL); | 1306 | sizeof(short), GFP_KERNEL); |
| 1307 | if (! chip->ac97_regs) | 1307 | if (! chip->ac97_regs) |
| 1308 | return -ENOMEM; | 1308 | return -ENOMEM; |
| 1309 | 1309 | ||
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 090dd4354a28..7442460583dd 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
| 30 | MODULE_DESCRIPTION("TempoTec HiFier driver"); | 30 | MODULE_DESCRIPTION("TempoTec HiFier driver"); |
| 31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL v2"); |
| 32 | 32 | ||
| 33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| 34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
| @@ -62,16 +62,28 @@ static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) | |||
| 62 | AK4396_WRITE | (reg << 8) | value); | 62 | AK4396_WRITE | (reg << 8) | value); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static void hifier_init(struct oxygen *chip) | 65 | static void update_ak4396_volume(struct oxygen *chip) |
| 66 | { | ||
| 67 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
| 68 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void hifier_registers_init(struct oxygen *chip) | ||
| 66 | { | 72 | { |
| 67 | struct hifier_data *data = chip->model_data; | 73 | struct hifier_data *data = chip->model_data; |
| 68 | 74 | ||
| 69 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
| 70 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | 75 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); |
| 71 | ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); | 76 | ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); |
| 72 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); | 77 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); |
| 73 | ak4396_write(chip, AK4396_LCH_ATT, 0); | 78 | update_ak4396_volume(chip); |
| 74 | ak4396_write(chip, AK4396_RCH_ATT, 0); | 79 | } |
| 80 | |||
| 81 | static void hifier_init(struct oxygen *chip) | ||
| 82 | { | ||
| 83 | struct hifier_data *data = chip->model_data; | ||
| 84 | |||
| 85 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
| 86 | hifier_registers_init(chip); | ||
| 75 | 87 | ||
| 76 | snd_component_add(chip->card, "AK4396"); | 88 | snd_component_add(chip->card, "AK4396"); |
| 77 | snd_component_add(chip->card, "CS5340"); | 89 | snd_component_add(chip->card, "CS5340"); |
| @@ -100,12 +112,6 @@ static void set_ak4396_params(struct oxygen *chip, | |||
| 100 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | 112 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); |
| 101 | } | 113 | } |
| 102 | 114 | ||
| 103 | static void update_ak4396_volume(struct oxygen *chip) | ||
| 104 | { | ||
| 105 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
| 106 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void update_ak4396_mute(struct oxygen *chip) | 115 | static void update_ak4396_mute(struct oxygen *chip) |
| 110 | { | 116 | { |
| 111 | struct hifier_data *data = chip->model_data; | 117 | struct hifier_data *data = chip->model_data; |
| @@ -140,6 +146,7 @@ static const struct oxygen_model model_hifier = { | |||
| 140 | .init = hifier_init, | 146 | .init = hifier_init, |
| 141 | .control_filter = hifier_control_filter, | 147 | .control_filter = hifier_control_filter, |
| 142 | .cleanup = hifier_cleanup, | 148 | .cleanup = hifier_cleanup, |
| 149 | .resume = hifier_registers_init, | ||
| 143 | .set_dac_params = set_ak4396_params, | 150 | .set_dac_params = set_ak4396_params, |
| 144 | .set_adc_params = set_cs5340_params, | 151 | .set_adc_params = set_cs5340_params, |
| 145 | .update_dac_volume = update_ak4396_volume, | 152 | .update_dac_volume = update_ak4396_volume, |
| @@ -180,6 +187,10 @@ static struct pci_driver hifier_driver = { | |||
| 180 | .id_table = hifier_ids, | 187 | .id_table = hifier_ids, |
| 181 | .probe = hifier_probe, | 188 | .probe = hifier_probe, |
| 182 | .remove = __devexit_p(oxygen_pci_remove), | 189 | .remove = __devexit_p(oxygen_pci_remove), |
| 190 | #ifdef CONFIG_PM | ||
| 191 | .suspend = oxygen_pci_suspend, | ||
| 192 | .resume = oxygen_pci_resume, | ||
| 193 | #endif | ||
| 183 | }; | 194 | }; |
| 184 | 195 | ||
| 185 | static int __init alsa_card_hifier_init(void) | 196 | static int __init alsa_card_hifier_init(void) |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 63f185c1ed1e..7c8ae31eb468 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
| @@ -43,7 +43,7 @@ | |||
| 43 | 43 | ||
| 44 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 44 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
| 45 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); | 45 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); |
| 46 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL v2"); |
| 47 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); | 47 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); |
| 48 | 48 | ||
| 49 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 49 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| @@ -80,6 +80,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); | |||
| 80 | 80 | ||
| 81 | struct generic_data { | 81 | struct generic_data { |
| 82 | u8 ak4396_ctl2; | 82 | u8 ak4396_ctl2; |
| 83 | u16 saved_wm8785_registers[2]; | ||
| 83 | }; | 84 | }; |
| 84 | 85 | ||
| 85 | static void ak4396_write(struct oxygen *chip, unsigned int codec, | 86 | static void ak4396_write(struct oxygen *chip, unsigned int codec, |
| @@ -99,20 +100,35 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec, | |||
| 99 | 100 | ||
| 100 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) | 101 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) |
| 101 | { | 102 | { |
| 103 | struct generic_data *data = chip->model_data; | ||
| 104 | |||
| 102 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | 105 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | |
| 103 | OXYGEN_SPI_DATA_LENGTH_2 | | 106 | OXYGEN_SPI_DATA_LENGTH_2 | |
| 104 | OXYGEN_SPI_CLOCK_160 | | 107 | OXYGEN_SPI_CLOCK_160 | |
| 105 | (3 << OXYGEN_SPI_CODEC_SHIFT) | | 108 | (3 << OXYGEN_SPI_CODEC_SHIFT) | |
| 106 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 109 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
| 107 | (reg << 9) | value); | 110 | (reg << 9) | value); |
| 111 | if (reg < ARRAY_SIZE(data->saved_wm8785_registers)) | ||
| 112 | data->saved_wm8785_registers[reg] = value; | ||
| 108 | } | 113 | } |
| 109 | 114 | ||
| 110 | static void ak4396_init(struct oxygen *chip) | 115 | static void update_ak4396_volume(struct oxygen *chip) |
| 116 | { | ||
| 117 | unsigned int i; | ||
| 118 | |||
| 119 | for (i = 0; i < 4; ++i) { | ||
| 120 | ak4396_write(chip, i, | ||
| 121 | AK4396_LCH_ATT, chip->dac_volume[i * 2]); | ||
| 122 | ak4396_write(chip, i, | ||
| 123 | AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | static void ak4396_registers_init(struct oxygen *chip) | ||
| 111 | { | 128 | { |
| 112 | struct generic_data *data = chip->model_data; | 129 | struct generic_data *data = chip->model_data; |
| 113 | unsigned int i; | 130 | unsigned int i; |
| 114 | 131 | ||
| 115 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
| 116 | for (i = 0; i < 4; ++i) { | 132 | for (i = 0; i < 4; ++i) { |
| 117 | ak4396_write(chip, i, | 133 | ak4396_write(chip, i, |
| 118 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | 134 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); |
| @@ -120,9 +136,16 @@ static void ak4396_init(struct oxygen *chip) | |||
| 120 | AK4396_CONTROL_2, data->ak4396_ctl2); | 136 | AK4396_CONTROL_2, data->ak4396_ctl2); |
| 121 | ak4396_write(chip, i, | 137 | ak4396_write(chip, i, |
| 122 | AK4396_CONTROL_3, AK4396_PCM); | 138 | AK4396_CONTROL_3, AK4396_PCM); |
| 123 | ak4396_write(chip, i, AK4396_LCH_ATT, 0); | ||
| 124 | ak4396_write(chip, i, AK4396_RCH_ATT, 0); | ||
| 125 | } | 139 | } |
| 140 | update_ak4396_volume(chip); | ||
| 141 | } | ||
| 142 | |||
| 143 | static void ak4396_init(struct oxygen *chip) | ||
| 144 | { | ||
| 145 | struct generic_data *data = chip->model_data; | ||
| 146 | |||
| 147 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
| 148 | ak4396_registers_init(chip); | ||
| 126 | snd_component_add(chip->card, "AK4396"); | 149 | snd_component_add(chip->card, "AK4396"); |
| 127 | } | 150 | } |
| 128 | 151 | ||
| @@ -133,12 +156,23 @@ static void ak5385_init(struct oxygen *chip) | |||
| 133 | snd_component_add(chip->card, "AK5385"); | 156 | snd_component_add(chip->card, "AK5385"); |
| 134 | } | 157 | } |
| 135 | 158 | ||
| 136 | static void wm8785_init(struct oxygen *chip) | 159 | static void wm8785_registers_init(struct oxygen *chip) |
| 137 | { | 160 | { |
| 161 | struct generic_data *data = chip->model_data; | ||
| 162 | |||
| 138 | wm8785_write(chip, WM8785_R7, 0); | 163 | wm8785_write(chip, WM8785_R7, 0); |
| 139 | wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE | | 164 | wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]); |
| 140 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST); | 165 | wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]); |
| 141 | wm8785_write(chip, WM8785_R1, WM8785_WL_24); | 166 | } |
| 167 | |||
| 168 | static void wm8785_init(struct oxygen *chip) | ||
| 169 | { | ||
| 170 | struct generic_data *data = chip->model_data; | ||
| 171 | |||
| 172 | data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE | | ||
| 173 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST; | ||
| 174 | data->saved_wm8785_registers[1] = WM8785_WL_24; | ||
| 175 | wm8785_registers_init(chip); | ||
| 142 | snd_component_add(chip->card, "WM8785"); | 176 | snd_component_add(chip->card, "WM8785"); |
| 143 | } | 177 | } |
| 144 | 178 | ||
| @@ -158,6 +192,12 @@ static void generic_cleanup(struct oxygen *chip) | |||
| 158 | { | 192 | { |
| 159 | } | 193 | } |
| 160 | 194 | ||
| 195 | static void generic_resume(struct oxygen *chip) | ||
| 196 | { | ||
| 197 | ak4396_registers_init(chip); | ||
| 198 | wm8785_registers_init(chip); | ||
| 199 | } | ||
| 200 | |||
| 161 | static void set_ak4396_params(struct oxygen *chip, | 201 | static void set_ak4396_params(struct oxygen *chip, |
| 162 | struct snd_pcm_hw_params *params) | 202 | struct snd_pcm_hw_params *params) |
| 163 | { | 203 | { |
| @@ -183,18 +223,6 @@ static void set_ak4396_params(struct oxygen *chip, | |||
| 183 | } | 223 | } |
| 184 | } | 224 | } |
| 185 | 225 | ||
| 186 | static void update_ak4396_volume(struct oxygen *chip) | ||
| 187 | { | ||
| 188 | unsigned int i; | ||
| 189 | |||
| 190 | for (i = 0; i < 4; ++i) { | ||
| 191 | ak4396_write(chip, i, | ||
| 192 | AK4396_LCH_ATT, chip->dac_volume[i * 2]); | ||
| 193 | ak4396_write(chip, i, | ||
| 194 | AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | static void update_ak4396_mute(struct oxygen *chip) | 226 | static void update_ak4396_mute(struct oxygen *chip) |
| 199 | { | 227 | { |
| 200 | struct generic_data *data = chip->model_data; | 228 | struct generic_data *data = chip->model_data; |
| @@ -256,6 +284,7 @@ static const struct oxygen_model model_generic = { | |||
| 256 | .owner = THIS_MODULE, | 284 | .owner = THIS_MODULE, |
| 257 | .init = generic_init, | 285 | .init = generic_init, |
| 258 | .cleanup = generic_cleanup, | 286 | .cleanup = generic_cleanup, |
| 287 | .resume = generic_resume, | ||
| 259 | .set_dac_params = set_ak4396_params, | 288 | .set_dac_params = set_ak4396_params, |
| 260 | .set_adc_params = set_wm8785_params, | 289 | .set_adc_params = set_wm8785_params, |
| 261 | .update_dac_volume = update_ak4396_volume, | 290 | .update_dac_volume = update_ak4396_volume, |
| @@ -283,6 +312,7 @@ static const struct oxygen_model model_meridian = { | |||
| 283 | .owner = THIS_MODULE, | 312 | .owner = THIS_MODULE, |
| 284 | .init = meridian_init, | 313 | .init = meridian_init, |
| 285 | .cleanup = generic_cleanup, | 314 | .cleanup = generic_cleanup, |
| 315 | .resume = ak4396_registers_init, | ||
| 286 | .set_dac_params = set_ak4396_params, | 316 | .set_dac_params = set_ak4396_params, |
| 287 | .set_adc_params = set_ak5385_params, | 317 | .set_adc_params = set_ak5385_params, |
| 288 | .update_dac_volume = update_ak4396_volume, | 318 | .update_dac_volume = update_ak4396_volume, |
| @@ -331,6 +361,10 @@ static struct pci_driver oxygen_driver = { | |||
| 331 | .id_table = oxygen_ids, | 361 | .id_table = oxygen_ids, |
| 332 | .probe = generic_oxygen_probe, | 362 | .probe = generic_oxygen_probe, |
| 333 | .remove = __devexit_p(oxygen_pci_remove), | 363 | .remove = __devexit_p(oxygen_pci_remove), |
| 364 | #ifdef CONFIG_PM | ||
| 365 | .suspend = oxygen_pci_suspend, | ||
| 366 | .resume = oxygen_pci_resume, | ||
| 367 | #endif | ||
| 334 | }; | 368 | }; |
| 335 | 369 | ||
| 336 | static int __init alsa_card_oxygen_init(void) | 370 | static int __init alsa_card_oxygen_init(void) |
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index a71c6e059260..74a644880074 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | #define PCM_AC97 5 | 16 | #define PCM_AC97 5 |
| 17 | #define PCM_COUNT 6 | 17 | #define PCM_COUNT 6 |
| 18 | 18 | ||
| 19 | #define OXYGEN_IO_SIZE 0x100 | ||
| 20 | |||
| 19 | /* model-specific configuration of outputs/inputs */ | 21 | /* model-specific configuration of outputs/inputs */ |
| 20 | #define PLAYBACK_0_TO_I2S 0x001 | 22 | #define PLAYBACK_0_TO_I2S 0x001 |
| 21 | #define PLAYBACK_1_TO_SPDIF 0x004 | 23 | #define PLAYBACK_1_TO_SPDIF 0x004 |
| @@ -78,6 +80,12 @@ struct oxygen { | |||
| 78 | struct work_struct spdif_input_bits_work; | 80 | struct work_struct spdif_input_bits_work; |
| 79 | struct work_struct gpio_work; | 81 | struct work_struct gpio_work; |
| 80 | wait_queue_head_t ac97_waitqueue; | 82 | wait_queue_head_t ac97_waitqueue; |
| 83 | union { | ||
| 84 | u8 _8[OXYGEN_IO_SIZE]; | ||
| 85 | __le16 _16[OXYGEN_IO_SIZE / 2]; | ||
| 86 | __le32 _32[OXYGEN_IO_SIZE / 4]; | ||
| 87 | } saved_registers; | ||
| 88 | u16 saved_ac97_registers[2][0x40]; | ||
| 81 | }; | 89 | }; |
| 82 | 90 | ||
| 83 | struct oxygen_model { | 91 | struct oxygen_model { |
| @@ -89,6 +97,8 @@ struct oxygen_model { | |||
| 89 | int (*control_filter)(struct snd_kcontrol_new *template); | 97 | int (*control_filter)(struct snd_kcontrol_new *template); |
| 90 | int (*mixer_init)(struct oxygen *chip); | 98 | int (*mixer_init)(struct oxygen *chip); |
| 91 | void (*cleanup)(struct oxygen *chip); | 99 | void (*cleanup)(struct oxygen *chip); |
| 100 | void (*suspend)(struct oxygen *chip); | ||
| 101 | void (*resume)(struct oxygen *chip); | ||
| 92 | void (*pcm_hardware_filter)(unsigned int channel, | 102 | void (*pcm_hardware_filter)(unsigned int channel, |
| 93 | struct snd_pcm_hardware *hardware); | 103 | struct snd_pcm_hardware *hardware); |
| 94 | void (*set_dac_params)(struct oxygen *chip, | 104 | void (*set_dac_params)(struct oxygen *chip, |
| @@ -117,6 +127,10 @@ struct oxygen_model { | |||
| 117 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | 127 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, |
| 118 | const struct oxygen_model *model); | 128 | const struct oxygen_model *model); |
| 119 | void oxygen_pci_remove(struct pci_dev *pci); | 129 | void oxygen_pci_remove(struct pci_dev *pci); |
| 130 | #ifdef CONFIG_PM | ||
| 131 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state); | ||
| 132 | int oxygen_pci_resume(struct pci_dev *pci); | ||
| 133 | #endif | ||
| 120 | 134 | ||
| 121 | /* oxygen_mixer.c */ | 135 | /* oxygen_mixer.c */ |
| 122 | 136 | ||
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 5569606ee87f..83f135f80df4 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c | |||
| @@ -44,18 +44,21 @@ EXPORT_SYMBOL(oxygen_read32); | |||
| 44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) | 44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) |
| 45 | { | 45 | { |
| 46 | outb(value, chip->addr + reg); | 46 | outb(value, chip->addr + reg); |
| 47 | chip->saved_registers._8[reg] = value; | ||
| 47 | } | 48 | } |
| 48 | EXPORT_SYMBOL(oxygen_write8); | 49 | EXPORT_SYMBOL(oxygen_write8); |
| 49 | 50 | ||
| 50 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) | 51 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) |
| 51 | { | 52 | { |
| 52 | outw(value, chip->addr + reg); | 53 | outw(value, chip->addr + reg); |
| 54 | chip->saved_registers._16[reg / 2] = cpu_to_le16(value); | ||
| 53 | } | 55 | } |
| 54 | EXPORT_SYMBOL(oxygen_write16); | 56 | EXPORT_SYMBOL(oxygen_write16); |
| 55 | 57 | ||
| 56 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) | 58 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) |
| 57 | { | 59 | { |
| 58 | outl(value, chip->addr + reg); | 60 | outl(value, chip->addr + reg); |
| 61 | chip->saved_registers._32[reg / 4] = cpu_to_le32(value); | ||
| 59 | } | 62 | } |
| 60 | EXPORT_SYMBOL(oxygen_write32); | 63 | EXPORT_SYMBOL(oxygen_write32); |
| 61 | 64 | ||
| @@ -63,7 +66,10 @@ void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, | |||
| 63 | u8 value, u8 mask) | 66 | u8 value, u8 mask) |
| 64 | { | 67 | { |
| 65 | u8 tmp = inb(chip->addr + reg); | 68 | u8 tmp = inb(chip->addr + reg); |
| 66 | outb((tmp & ~mask) | (value & mask), chip->addr + reg); | 69 | tmp &= ~mask; |
| 70 | tmp |= value & mask; | ||
| 71 | outb(tmp, chip->addr + reg); | ||
| 72 | chip->saved_registers._8[reg] = tmp; | ||
| 67 | } | 73 | } |
| 68 | EXPORT_SYMBOL(oxygen_write8_masked); | 74 | EXPORT_SYMBOL(oxygen_write8_masked); |
| 69 | 75 | ||
| @@ -71,7 +77,10 @@ void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, | |||
| 71 | u16 value, u16 mask) | 77 | u16 value, u16 mask) |
| 72 | { | 78 | { |
| 73 | u16 tmp = inw(chip->addr + reg); | 79 | u16 tmp = inw(chip->addr + reg); |
| 74 | outw((tmp & ~mask) | (value & mask), chip->addr + reg); | 80 | tmp &= ~mask; |
| 81 | tmp |= value & mask; | ||
| 82 | outw(tmp, chip->addr + reg); | ||
| 83 | chip->saved_registers._16[reg / 2] = cpu_to_le16(tmp); | ||
| 75 | } | 84 | } |
| 76 | EXPORT_SYMBOL(oxygen_write16_masked); | 85 | EXPORT_SYMBOL(oxygen_write16_masked); |
| 77 | 86 | ||
| @@ -79,7 +88,10 @@ void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, | |||
| 79 | u32 value, u32 mask) | 88 | u32 value, u32 mask) |
| 80 | { | 89 | { |
| 81 | u32 tmp = inl(chip->addr + reg); | 90 | u32 tmp = inl(chip->addr + reg); |
| 82 | outl((tmp & ~mask) | (value & mask), chip->addr + reg); | 91 | tmp &= ~mask; |
| 92 | tmp |= value & mask; | ||
| 93 | outl(tmp, chip->addr + reg); | ||
| 94 | chip->saved_registers._32[reg / 4] = cpu_to_le32(tmp); | ||
| 83 | } | 95 | } |
| 84 | EXPORT_SYMBOL(oxygen_write32_masked); | 96 | EXPORT_SYMBOL(oxygen_write32_masked); |
| 85 | 97 | ||
| @@ -128,8 +140,10 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, | |||
| 128 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); | 140 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); |
| 129 | /* require two "completed" writes, just to be sure */ | 141 | /* require two "completed" writes, just to be sure */ |
| 130 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && | 142 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && |
| 131 | ++succeeded >= 2) | 143 | ++succeeded >= 2) { |
| 144 | chip->saved_ac97_registers[codec][index / 2] = data; | ||
| 132 | return; | 145 | return; |
| 146 | } | ||
| 133 | } | 147 | } |
| 134 | snd_printk(KERN_ERR "AC'97 write timeout\n"); | 148 | snd_printk(KERN_ERR "AC'97 write timeout\n"); |
| 135 | } | 149 | } |
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 897697d43506..22f37851045e 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | 32 | ||
| 33 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 33 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
| 34 | MODULE_DESCRIPTION("C-Media CMI8788 helper library"); | 34 | MODULE_DESCRIPTION("C-Media CMI8788 helper library"); |
| 35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL v2"); |
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) | 38 | static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) |
| @@ -173,7 +173,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
| 173 | int i, j; | 173 | int i, j; |
| 174 | 174 | ||
| 175 | snd_iprintf(buffer, "CMI8788\n\n"); | 175 | snd_iprintf(buffer, "CMI8788\n\n"); |
| 176 | for (i = 0; i < 0x100; i += 0x10) { | 176 | for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { |
| 177 | snd_iprintf(buffer, "%02x:", i); | 177 | snd_iprintf(buffer, "%02x:", i); |
| 178 | for (j = 0; j < 0x10; ++j) | 178 | for (j = 0; j < 0x10; ++j) |
| 179 | snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j)); | 179 | snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j)); |
| @@ -314,6 +314,10 @@ static void oxygen_init(struct oxygen *chip) | |||
| 314 | OXYGEN_SPDIF_LOCK_MASK | | 314 | OXYGEN_SPDIF_LOCK_MASK | |
| 315 | OXYGEN_SPDIF_RATE_MASK); | 315 | OXYGEN_SPDIF_RATE_MASK); |
| 316 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); | 316 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); |
| 317 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
| 318 | OXYGEN_2WIRE_LENGTH_8 | | ||
| 319 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
| 320 | OXYGEN_2WIRE_SPEED_STANDARD); | ||
| 317 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); | 321 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); |
| 318 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); | 322 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); |
| 319 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); | 323 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); |
| @@ -455,7 +459,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
| 455 | } | 459 | } |
| 456 | 460 | ||
| 457 | if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || | 461 | if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || |
| 458 | pci_resource_len(pci, 0) < 0x100) { | 462 | pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) { |
| 459 | snd_printk(KERN_ERR "invalid PCI I/O range\n"); | 463 | snd_printk(KERN_ERR "invalid PCI I/O range\n"); |
| 460 | err = -ENXIO; | 464 | err = -ENXIO; |
| 461 | goto err_pci_regions; | 465 | goto err_pci_regions; |
| @@ -534,3 +538,99 @@ void oxygen_pci_remove(struct pci_dev *pci) | |||
| 534 | pci_set_drvdata(pci, NULL); | 538 | pci_set_drvdata(pci, NULL); |
| 535 | } | 539 | } |
| 536 | EXPORT_SYMBOL(oxygen_pci_remove); | 540 | EXPORT_SYMBOL(oxygen_pci_remove); |
| 541 | |||
| 542 | #ifdef CONFIG_PM | ||
| 543 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state) | ||
| 544 | { | ||
| 545 | struct snd_card *card = pci_get_drvdata(pci); | ||
| 546 | struct oxygen *chip = card->private_data; | ||
| 547 | unsigned int i, saved_interrupt_mask; | ||
| 548 | |||
| 549 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
| 550 | |||
| 551 | for (i = 0; i < PCM_COUNT; ++i) | ||
| 552 | if (chip->streams[i]) | ||
| 553 | snd_pcm_suspend(chip->streams[i]); | ||
| 554 | |||
| 555 | if (chip->model->suspend) | ||
| 556 | chip->model->suspend(chip); | ||
| 557 | |||
| 558 | spin_lock_irq(&chip->reg_lock); | ||
| 559 | saved_interrupt_mask = chip->interrupt_mask; | ||
| 560 | chip->interrupt_mask = 0; | ||
| 561 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
| 562 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
| 563 | spin_unlock_irq(&chip->reg_lock); | ||
| 564 | |||
| 565 | synchronize_irq(chip->irq); | ||
| 566 | flush_scheduled_work(); | ||
| 567 | chip->interrupt_mask = saved_interrupt_mask; | ||
| 568 | |||
| 569 | pci_disable_device(pci); | ||
| 570 | pci_save_state(pci); | ||
| 571 | pci_set_power_state(pci, pci_choose_state(pci, state)); | ||
| 572 | return 0; | ||
| 573 | } | ||
| 574 | EXPORT_SYMBOL(oxygen_pci_suspend); | ||
| 575 | |||
| 576 | static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = { | ||
| 577 | 0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff, | ||
| 578 | 0x00300000, 0x00000fe4, 0x0ff7001f, 0x00000000 | ||
| 579 | }; | ||
| 580 | static const u32 ac97_registers_to_restore[2][0x40 / 32] = { | ||
| 581 | { 0x18284fa2, 0x03060000 }, | ||
| 582 | { 0x00007fa6, 0x00200000 } | ||
| 583 | }; | ||
| 584 | |||
| 585 | static inline int is_bit_set(const u32 *bitmap, unsigned int bit) | ||
| 586 | { | ||
| 587 | return bitmap[bit / 32] & (1 << (bit & 31)); | ||
| 588 | } | ||
| 589 | |||
| 590 | static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec) | ||
| 591 | { | ||
| 592 | unsigned int i; | ||
| 593 | |||
| 594 | oxygen_write_ac97(chip, codec, AC97_RESET, 0); | ||
| 595 | msleep(1); | ||
| 596 | for (i = 1; i < 0x40; ++i) | ||
| 597 | if (is_bit_set(ac97_registers_to_restore[codec], i)) | ||
| 598 | oxygen_write_ac97(chip, codec, i * 2, | ||
| 599 | chip->saved_ac97_registers[codec][i]); | ||
| 600 | } | ||
| 601 | |||
| 602 | int oxygen_pci_resume(struct pci_dev *pci) | ||
| 603 | { | ||
| 604 | struct snd_card *card = pci_get_drvdata(pci); | ||
| 605 | struct oxygen *chip = card->private_data; | ||
| 606 | unsigned int i; | ||
| 607 | |||
| 608 | pci_set_power_state(pci, PCI_D0); | ||
| 609 | pci_restore_state(pci); | ||
| 610 | if (pci_enable_device(pci) < 0) { | ||
| 611 | snd_printk(KERN_ERR "cannot reenable device"); | ||
| 612 | snd_card_disconnect(card); | ||
| 613 | return -EIO; | ||
| 614 | } | ||
| 615 | pci_set_master(pci); | ||
| 616 | |||
| 617 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
| 618 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
| 619 | for (i = 0; i < OXYGEN_IO_SIZE; ++i) | ||
| 620 | if (is_bit_set(registers_to_restore, i)) | ||
| 621 | oxygen_write8(chip, i, chip->saved_registers._8[i]); | ||
| 622 | if (chip->has_ac97_0) | ||
| 623 | oxygen_restore_ac97(chip, 0); | ||
| 624 | if (chip->has_ac97_1) | ||
| 625 | oxygen_restore_ac97(chip, 1); | ||
| 626 | |||
| 627 | if (chip->model->resume) | ||
| 628 | chip->model->resume(chip); | ||
| 629 | |||
| 630 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
| 631 | |||
| 632 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
| 633 | return 0; | ||
| 634 | } | ||
| 635 | EXPORT_SYMBOL(oxygen_pci_resume); | ||
| 636 | #endif /* CONFIG_PM */ | ||
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index b17c405e069d..c4ad65a3406f 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
| @@ -24,6 +24,16 @@ | |||
| 24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
| 25 | #include "oxygen.h" | 25 | #include "oxygen.h" |
| 26 | 26 | ||
| 27 | /* most DMA channels have a 16-bit counter for 32-bit words */ | ||
| 28 | #define BUFFER_BYTES_MAX ((1 << 16) * 4) | ||
| 29 | /* the multichannel DMA channel has a 24-bit counter */ | ||
| 30 | #define BUFFER_BYTES_MAX_MULTICH ((1 << 24) * 4) | ||
| 31 | |||
| 32 | #define PERIOD_BYTES_MIN 64 | ||
| 33 | |||
| 34 | #define DEFAULT_BUFFER_BYTES (BUFFER_BYTES_MAX / 2) | ||
| 35 | #define DEFAULT_BUFFER_BYTES_MULTICH (1024 * 1024) | ||
| 36 | |||
| 27 | static const struct snd_pcm_hardware oxygen_stereo_hardware = { | 37 | static const struct snd_pcm_hardware oxygen_stereo_hardware = { |
| 28 | .info = SNDRV_PCM_INFO_MMAP | | 38 | .info = SNDRV_PCM_INFO_MMAP | |
| 29 | SNDRV_PCM_INFO_MMAP_VALID | | 39 | SNDRV_PCM_INFO_MMAP_VALID | |
| @@ -44,11 +54,11 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { | |||
| 44 | .rate_max = 192000, | 54 | .rate_max = 192000, |
| 45 | .channels_min = 2, | 55 | .channels_min = 2, |
| 46 | .channels_max = 2, | 56 | .channels_max = 2, |
| 47 | .buffer_bytes_max = 256 * 1024, | 57 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
| 48 | .period_bytes_min = 128, | 58 | .period_bytes_min = PERIOD_BYTES_MIN, |
| 49 | .period_bytes_max = 128 * 1024, | 59 | .period_bytes_max = BUFFER_BYTES_MAX / 2, |
| 50 | .periods_min = 2, | 60 | .periods_min = 2, |
| 51 | .periods_max = 2048, | 61 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
| 52 | }; | 62 | }; |
| 53 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | 63 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { |
| 54 | .info = SNDRV_PCM_INFO_MMAP | | 64 | .info = SNDRV_PCM_INFO_MMAP | |
| @@ -70,11 +80,11 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | |||
| 70 | .rate_max = 192000, | 80 | .rate_max = 192000, |
| 71 | .channels_min = 2, | 81 | .channels_min = 2, |
| 72 | .channels_max = 8, | 82 | .channels_max = 8, |
| 73 | .buffer_bytes_max = 2048 * 1024, | 83 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
| 74 | .period_bytes_min = 128, | 84 | .period_bytes_min = PERIOD_BYTES_MIN, |
| 75 | .period_bytes_max = 256 * 1024, | 85 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, |
| 76 | .periods_min = 2, | 86 | .periods_min = 2, |
| 77 | .periods_max = 16384, | 87 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, |
| 78 | }; | 88 | }; |
| 79 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { | 89 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { |
| 80 | .info = SNDRV_PCM_INFO_MMAP | | 90 | .info = SNDRV_PCM_INFO_MMAP | |
| @@ -88,11 +98,11 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { | |||
| 88 | .rate_max = 48000, | 98 | .rate_max = 48000, |
| 89 | .channels_min = 2, | 99 | .channels_min = 2, |
| 90 | .channels_max = 2, | 100 | .channels_max = 2, |
| 91 | .buffer_bytes_max = 256 * 1024, | 101 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
| 92 | .period_bytes_min = 128, | 102 | .period_bytes_min = PERIOD_BYTES_MIN, |
| 93 | .period_bytes_max = 128 * 1024, | 103 | .period_bytes_max = BUFFER_BYTES_MAX / 2, |
| 94 | .periods_min = 2, | 104 | .periods_min = 2, |
| 95 | .periods_max = 2048, | 105 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
| 96 | }; | 106 | }; |
| 97 | 107 | ||
| 98 | static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { | 108 | static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { |
| @@ -155,6 +165,12 @@ static int oxygen_open(struct snd_pcm_substream *substream, | |||
| 155 | if (err < 0) | 165 | if (err < 0) |
| 156 | return err; | 166 | return err; |
| 157 | } | 167 | } |
| 168 | if (channel == PCM_MULTICH) { | ||
| 169 | err = snd_pcm_hw_constraint_minmax | ||
| 170 | (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000); | ||
| 171 | if (err < 0) | ||
| 172 | return err; | ||
| 173 | } | ||
| 158 | snd_pcm_set_sync(substream); | 174 | snd_pcm_set_sync(substream); |
| 159 | chip->streams[channel] = substream; | 175 | chip->streams[channel] = substream; |
| 160 | 176 | ||
| @@ -517,6 +533,7 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 517 | switch (cmd) { | 533 | switch (cmd) { |
| 518 | case SNDRV_PCM_TRIGGER_STOP: | 534 | case SNDRV_PCM_TRIGGER_STOP: |
| 519 | case SNDRV_PCM_TRIGGER_START: | 535 | case SNDRV_PCM_TRIGGER_START: |
| 536 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 520 | pausing = 0; | 537 | pausing = 0; |
| 521 | break; | 538 | break; |
| 522 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 539 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
| @@ -663,12 +680,14 @@ int oxygen_pcm_init(struct oxygen *chip) | |||
| 663 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, | 680 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, |
| 664 | SNDRV_DMA_TYPE_DEV, | 681 | SNDRV_DMA_TYPE_DEV, |
| 665 | snd_dma_pci_data(chip->pci), | 682 | snd_dma_pci_data(chip->pci), |
| 666 | 512 * 1024, 2048 * 1024); | 683 | DEFAULT_BUFFER_BYTES_MULTICH, |
| 684 | BUFFER_BYTES_MAX_MULTICH); | ||
| 667 | if (ins) | 685 | if (ins) |
| 668 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, | 686 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, |
| 669 | SNDRV_DMA_TYPE_DEV, | 687 | SNDRV_DMA_TYPE_DEV, |
| 670 | snd_dma_pci_data(chip->pci), | 688 | snd_dma_pci_data(chip->pci), |
| 671 | 128 * 1024, 256 * 1024); | 689 | DEFAULT_BUFFER_BYTES, |
| 690 | BUFFER_BYTES_MAX); | ||
| 672 | } | 691 | } |
| 673 | 692 | ||
| 674 | outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF); | 693 | outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF); |
| @@ -688,7 +707,8 @@ int oxygen_pcm_init(struct oxygen *chip) | |||
| 688 | strcpy(pcm->name, "Digital"); | 707 | strcpy(pcm->name, "Digital"); |
| 689 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 708 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
| 690 | snd_dma_pci_data(chip->pci), | 709 | snd_dma_pci_data(chip->pci), |
| 691 | 128 * 1024, 256 * 1024); | 710 | DEFAULT_BUFFER_BYTES, |
| 711 | BUFFER_BYTES_MAX); | ||
| 692 | } | 712 | } |
| 693 | 713 | ||
| 694 | if (chip->has_ac97_1) { | 714 | if (chip->has_ac97_1) { |
| @@ -718,7 +738,8 @@ int oxygen_pcm_init(struct oxygen *chip) | |||
| 718 | strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); | 738 | strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); |
| 719 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 739 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
| 720 | snd_dma_pci_data(chip->pci), | 740 | snd_dma_pci_data(chip->pci), |
| 721 | 128 * 1024, 256 * 1024); | 741 | DEFAULT_BUFFER_BYTES, |
| 742 | BUFFER_BYTES_MAX); | ||
| 722 | } | 743 | } |
| 723 | return 0; | 744 | return 0; |
| 724 | } | 745 | } |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 7f84fa5deca2..9a2c16bf94e0 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
| @@ -79,7 +79,7 @@ | |||
| 79 | 79 | ||
| 80 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 80 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
| 81 | MODULE_DESCRIPTION("Asus AVx00 driver"); | 81 | MODULE_DESCRIPTION("Asus AVx00 driver"); |
| 82 | MODULE_LICENSE("GPL"); | 82 | MODULE_LICENSE("GPL v2"); |
| 83 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); | 83 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); |
| 84 | 84 | ||
| 85 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 85 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| @@ -132,6 +132,9 @@ struct xonar_data { | |||
| 132 | u8 ext_power_int_reg; | 132 | u8 ext_power_int_reg; |
| 133 | u8 ext_power_bit; | 133 | u8 ext_power_bit; |
| 134 | u8 has_power; | 134 | u8 has_power; |
| 135 | u8 pcm1796_oversampling; | ||
| 136 | u8 cs4398_fm; | ||
| 137 | u8 cs4362a_fm; | ||
| 135 | }; | 138 | }; |
| 136 | 139 | ||
| 137 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, | 140 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, |
| @@ -159,6 +162,14 @@ static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) | |||
| 159 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); | 162 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); |
| 160 | } | 163 | } |
| 161 | 164 | ||
| 165 | static void xonar_enable_output(struct oxygen *chip) | ||
| 166 | { | ||
| 167 | struct xonar_data *data = chip->model_data; | ||
| 168 | |||
| 169 | msleep(data->anti_pop_delay); | ||
| 170 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); | ||
| 171 | } | ||
| 172 | |||
| 162 | static void xonar_common_init(struct oxygen *chip) | 173 | static void xonar_common_init(struct oxygen *chip) |
| 163 | { | 174 | { |
| 164 | struct xonar_data *data = chip->model_data; | 175 | struct xonar_data *data = chip->model_data; |
| @@ -170,32 +181,59 @@ static void xonar_common_init(struct oxygen *chip) | |||
| 170 | data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) | 181 | data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) |
| 171 | & data->ext_power_bit); | 182 | & data->ext_power_bit); |
| 172 | } | 183 | } |
| 173 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); | 184 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
| 185 | GPIO_CS53x1_M_MASK | data->output_enable_bit); | ||
| 174 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | 186 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, |
| 175 | GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); | 187 | GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); |
| 176 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | 188 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); |
| 177 | msleep(data->anti_pop_delay); | 189 | xonar_enable_output(chip); |
| 178 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); | ||
| 179 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); | ||
| 180 | } | 190 | } |
| 181 | 191 | ||
| 182 | static void xonar_d2_init(struct oxygen *chip) | 192 | static void update_pcm1796_volume(struct oxygen *chip) |
| 183 | { | 193 | { |
| 184 | struct xonar_data *data = chip->model_data; | ||
| 185 | unsigned int i; | 194 | unsigned int i; |
| 186 | 195 | ||
| 187 | data->anti_pop_delay = 300; | 196 | for (i = 0; i < 4; ++i) { |
| 188 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | 197 | pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); |
| 198 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | static void update_pcm1796_mute(struct oxygen *chip) | ||
| 203 | { | ||
| 204 | unsigned int i; | ||
| 205 | u8 value; | ||
| 206 | |||
| 207 | value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | ||
| 208 | if (chip->dac_mute) | ||
| 209 | value |= PCM1796_MUTE; | ||
| 210 | for (i = 0; i < 4; ++i) | ||
| 211 | pcm1796_write(chip, i, 18, value); | ||
| 212 | } | ||
| 213 | |||
| 214 | static void pcm1796_init(struct oxygen *chip) | ||
| 215 | { | ||
| 216 | struct xonar_data *data = chip->model_data; | ||
| 217 | unsigned int i; | ||
| 189 | 218 | ||
| 190 | for (i = 0; i < 4; ++i) { | 219 | for (i = 0; i < 4; ++i) { |
| 191 | pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED | | ||
| 192 | PCM1796_FMT_24_LJUST | PCM1796_ATLD); | ||
| 193 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | 220 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); |
| 194 | pcm1796_write(chip, i, 20, PCM1796_OS_64); | 221 | pcm1796_write(chip, i, 20, data->pcm1796_oversampling); |
| 195 | pcm1796_write(chip, i, 21, 0); | 222 | pcm1796_write(chip, i, 21, 0); |
| 196 | pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */ | ||
| 197 | pcm1796_write(chip, i, 17, 0x0f); | ||
| 198 | } | 223 | } |
| 224 | update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */ | ||
| 225 | update_pcm1796_volume(chip); | ||
| 226 | } | ||
| 227 | |||
| 228 | static void xonar_d2_init(struct oxygen *chip) | ||
| 229 | { | ||
| 230 | struct xonar_data *data = chip->model_data; | ||
| 231 | |||
| 232 | data->anti_pop_delay = 300; | ||
| 233 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | ||
| 234 | data->pcm1796_oversampling = PCM1796_OS_64; | ||
| 235 | |||
| 236 | pcm1796_init(chip); | ||
| 199 | 237 | ||
| 200 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); | 238 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); |
| 201 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); | 239 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); |
| @@ -217,31 +255,47 @@ static void xonar_d2x_init(struct oxygen *chip) | |||
| 217 | xonar_d2_init(chip); | 255 | xonar_d2_init(chip); |
| 218 | } | 256 | } |
| 219 | 257 | ||
| 220 | static void xonar_dx_init(struct oxygen *chip) | 258 | static void update_cs4362a_volumes(struct oxygen *chip) |
| 221 | { | 259 | { |
| 222 | struct xonar_data *data = chip->model_data; | 260 | u8 mute; |
| 223 | 261 | ||
| 224 | data->anti_pop_delay = 800; | 262 | mute = chip->dac_mute ? CS4362A_MUTE : 0; |
| 225 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | 263 | cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); |
| 226 | data->ext_power_reg = OXYGEN_GPI_DATA; | 264 | cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); |
| 227 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 265 | cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); |
| 228 | data->ext_power_bit = GPI_DX_EXT_POWER; | 266 | cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); |
| 267 | cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); | ||
| 268 | cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); | ||
| 269 | } | ||
| 229 | 270 | ||
| 230 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 271 | static void update_cs43xx_volume(struct oxygen *chip) |
| 231 | OXYGEN_2WIRE_LENGTH_8 | | 272 | { |
| 232 | OXYGEN_2WIRE_INTERRUPT_MASK | | 273 | cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); |
| 233 | OXYGEN_2WIRE_SPEED_FAST); | 274 | cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); |
| 275 | update_cs4362a_volumes(chip); | ||
| 276 | } | ||
| 277 | |||
| 278 | static void update_cs43xx_mute(struct oxygen *chip) | ||
| 279 | { | ||
| 280 | u8 reg; | ||
| 281 | |||
| 282 | reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; | ||
| 283 | if (chip->dac_mute) | ||
| 284 | reg |= CS4398_MUTE_B | CS4398_MUTE_A; | ||
| 285 | cs4398_write(chip, 4, reg); | ||
| 286 | update_cs4362a_volumes(chip); | ||
| 287 | } | ||
| 288 | |||
| 289 | static void cs43xx_init(struct oxygen *chip) | ||
| 290 | { | ||
| 291 | struct xonar_data *data = chip->model_data; | ||
| 234 | 292 | ||
| 235 | /* set CPEN (control port mode) and power down */ | 293 | /* set CPEN (control port mode) and power down */ |
| 236 | cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); | 294 | cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); |
| 237 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); | 295 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); |
| 238 | /* configure */ | 296 | /* configure */ |
| 239 | cs4398_write(chip, 2, CS4398_FM_SINGLE | | 297 | cs4398_write(chip, 2, data->cs4398_fm); |
| 240 | CS4398_DEM_NONE | CS4398_DIF_LJUST); | ||
| 241 | cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); | 298 | cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); |
| 242 | cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE); | ||
| 243 | cs4398_write(chip, 5, 0xfe); | ||
| 244 | cs4398_write(chip, 6, 0xfe); | ||
| 245 | cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | | 299 | cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | |
| 246 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); | 300 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); |
| 247 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); | 301 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); |
| @@ -249,21 +303,35 @@ static void xonar_dx_init(struct oxygen *chip) | |||
| 249 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); | 303 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); |
| 250 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); | 304 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); |
| 251 | cs4362a_write(chip, 0x05, 0); | 305 | cs4362a_write(chip, 0x05, 0); |
| 252 | cs4362a_write(chip, 0x06, CS4362A_FM_SINGLE | | 306 | cs4362a_write(chip, 0x06, data->cs4362a_fm); |
| 253 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | 307 | cs4362a_write(chip, 0x09, data->cs4362a_fm); |
| 254 | cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE); | 308 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); |
| 255 | cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE); | 309 | update_cs43xx_volume(chip); |
| 256 | cs4362a_write(chip, 0x09, CS4362A_FM_SINGLE | | 310 | update_cs43xx_mute(chip); |
| 257 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
| 258 | cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE); | ||
| 259 | cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE); | ||
| 260 | cs4362a_write(chip, 0x0c, CS4362A_FM_SINGLE | | ||
| 261 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
| 262 | cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE); | ||
| 263 | cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE); | ||
| 264 | /* clear power down */ | 311 | /* clear power down */ |
| 265 | cs4398_write(chip, 8, CS4398_CPEN); | 312 | cs4398_write(chip, 8, CS4398_CPEN); |
| 266 | cs4362a_write(chip, 0x01, CS4362A_CPEN); | 313 | cs4362a_write(chip, 0x01, CS4362A_CPEN); |
| 314 | } | ||
| 315 | |||
| 316 | static void xonar_dx_init(struct oxygen *chip) | ||
| 317 | { | ||
| 318 | struct xonar_data *data = chip->model_data; | ||
| 319 | |||
| 320 | data->anti_pop_delay = 800; | ||
| 321 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | ||
| 322 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
| 323 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
| 324 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
| 325 | data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; | ||
| 326 | data->cs4362a_fm = CS4362A_FM_SINGLE | | ||
| 327 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | ||
| 328 | |||
| 329 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
| 330 | OXYGEN_2WIRE_LENGTH_8 | | ||
| 331 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
| 332 | OXYGEN_2WIRE_SPEED_FAST); | ||
| 333 | |||
| 334 | cs43xx_init(chip); | ||
| 267 | 335 | ||
| 268 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | 336 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
| 269 | GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); | 337 | GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); |
| @@ -291,37 +359,28 @@ static void xonar_dx_cleanup(struct oxygen *chip) | |||
| 291 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); | 359 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); |
| 292 | } | 360 | } |
| 293 | 361 | ||
| 294 | static void set_pcm1796_params(struct oxygen *chip, | 362 | static void xonar_d2_resume(struct oxygen *chip) |
| 295 | struct snd_pcm_hw_params *params) | ||
| 296 | { | 363 | { |
| 297 | unsigned int i; | 364 | pcm1796_init(chip); |
| 298 | u8 value; | 365 | xonar_enable_output(chip); |
| 299 | |||
| 300 | value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | ||
| 301 | for (i = 0; i < 4; ++i) | ||
| 302 | pcm1796_write(chip, i, 20, value); | ||
| 303 | } | 366 | } |
| 304 | 367 | ||
| 305 | static void update_pcm1796_volume(struct oxygen *chip) | 368 | static void xonar_dx_resume(struct oxygen *chip) |
| 306 | { | 369 | { |
| 307 | unsigned int i; | 370 | cs43xx_init(chip); |
| 308 | 371 | xonar_enable_output(chip); | |
| 309 | for (i = 0; i < 4; ++i) { | ||
| 310 | pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); | ||
| 311 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); | ||
| 312 | } | ||
| 313 | } | 372 | } |
| 314 | 373 | ||
| 315 | static void update_pcm1796_mute(struct oxygen *chip) | 374 | static void set_pcm1796_params(struct oxygen *chip, |
| 375 | struct snd_pcm_hw_params *params) | ||
| 316 | { | 376 | { |
| 377 | struct xonar_data *data = chip->model_data; | ||
| 317 | unsigned int i; | 378 | unsigned int i; |
| 318 | u8 value; | ||
| 319 | 379 | ||
| 320 | value = PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 380 | data->pcm1796_oversampling = |
| 321 | if (chip->dac_mute) | 381 | params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; |
| 322 | value |= PCM1796_MUTE; | ||
| 323 | for (i = 0; i < 4; ++i) | 382 | for (i = 0; i < 4; ++i) |
| 324 | pcm1796_write(chip, i, 18, value); | 383 | pcm1796_write(chip, i, 20, data->pcm1796_oversampling); |
| 325 | } | 384 | } |
| 326 | 385 | ||
| 327 | static void set_cs53x1_params(struct oxygen *chip, | 386 | static void set_cs53x1_params(struct oxygen *chip, |
| @@ -342,55 +401,24 @@ static void set_cs53x1_params(struct oxygen *chip, | |||
| 342 | static void set_cs43xx_params(struct oxygen *chip, | 401 | static void set_cs43xx_params(struct oxygen *chip, |
| 343 | struct snd_pcm_hw_params *params) | 402 | struct snd_pcm_hw_params *params) |
| 344 | { | 403 | { |
| 345 | u8 fm_cs4398, fm_cs4362a; | 404 | struct xonar_data *data = chip->model_data; |
| 346 | 405 | ||
| 347 | fm_cs4398 = CS4398_DEM_NONE | CS4398_DIF_LJUST; | 406 | data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; |
| 348 | fm_cs4362a = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | 407 | data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
| 349 | if (params_rate(params) <= 50000) { | 408 | if (params_rate(params) <= 50000) { |
| 350 | fm_cs4398 |= CS4398_FM_SINGLE; | 409 | data->cs4398_fm |= CS4398_FM_SINGLE; |
| 351 | fm_cs4362a |= CS4362A_FM_SINGLE; | 410 | data->cs4362a_fm |= CS4362A_FM_SINGLE; |
| 352 | } else if (params_rate(params) <= 100000) { | 411 | } else if (params_rate(params) <= 100000) { |
| 353 | fm_cs4398 |= CS4398_FM_DOUBLE; | 412 | data->cs4398_fm |= CS4398_FM_DOUBLE; |
| 354 | fm_cs4362a |= CS4362A_FM_DOUBLE; | 413 | data->cs4362a_fm |= CS4362A_FM_DOUBLE; |
| 355 | } else { | 414 | } else { |
| 356 | fm_cs4398 |= CS4398_FM_QUAD; | 415 | data->cs4398_fm |= CS4398_FM_QUAD; |
| 357 | fm_cs4362a |= CS4362A_FM_QUAD; | 416 | data->cs4362a_fm |= CS4362A_FM_QUAD; |
| 358 | } | 417 | } |
| 359 | cs4398_write(chip, 2, fm_cs4398); | 418 | cs4398_write(chip, 2, data->cs4398_fm); |
| 360 | cs4362a_write(chip, 0x06, fm_cs4362a); | 419 | cs4362a_write(chip, 0x06, data->cs4362a_fm); |
| 361 | cs4362a_write(chip, 0x09, fm_cs4362a); | 420 | cs4362a_write(chip, 0x09, data->cs4362a_fm); |
| 362 | cs4362a_write(chip, 0x0c, fm_cs4362a); | 421 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); |
| 363 | } | ||
| 364 | |||
| 365 | static void update_cs4362a_volumes(struct oxygen *chip) | ||
| 366 | { | ||
| 367 | u8 mute; | ||
| 368 | |||
| 369 | mute = chip->dac_mute ? CS4362A_MUTE : 0; | ||
| 370 | cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); | ||
| 371 | cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); | ||
| 372 | cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); | ||
| 373 | cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); | ||
| 374 | cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); | ||
| 375 | cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); | ||
| 376 | } | ||
| 377 | |||
| 378 | static void update_cs43xx_volume(struct oxygen *chip) | ||
| 379 | { | ||
| 380 | cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); | ||
| 381 | cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); | ||
| 382 | update_cs4362a_volumes(chip); | ||
| 383 | } | ||
| 384 | |||
| 385 | static void update_cs43xx_mute(struct oxygen *chip) | ||
| 386 | { | ||
| 387 | u8 reg; | ||
| 388 | |||
| 389 | reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; | ||
| 390 | if (chip->dac_mute) | ||
| 391 | reg |= CS4398_MUTE_B | CS4398_MUTE_A; | ||
| 392 | cs4398_write(chip, 4, reg); | ||
| 393 | update_cs4362a_volumes(chip); | ||
| 394 | } | 422 | } |
| 395 | 423 | ||
| 396 | static void xonar_gpio_changed(struct oxygen *chip) | 424 | static void xonar_gpio_changed(struct oxygen *chip) |
| @@ -535,6 +563,8 @@ static const struct oxygen_model xonar_models[] = { | |||
| 535 | .control_filter = xonar_d2_control_filter, | 563 | .control_filter = xonar_d2_control_filter, |
| 536 | .mixer_init = xonar_mixer_init, | 564 | .mixer_init = xonar_mixer_init, |
| 537 | .cleanup = xonar_cleanup, | 565 | .cleanup = xonar_cleanup, |
| 566 | .suspend = xonar_cleanup, | ||
| 567 | .resume = xonar_d2_resume, | ||
| 538 | .set_dac_params = set_pcm1796_params, | 568 | .set_dac_params = set_pcm1796_params, |
| 539 | .set_adc_params = set_cs53x1_params, | 569 | .set_adc_params = set_cs53x1_params, |
| 540 | .update_dac_volume = update_pcm1796_volume, | 570 | .update_dac_volume = update_pcm1796_volume, |
| @@ -563,6 +593,8 @@ static const struct oxygen_model xonar_models[] = { | |||
| 563 | .control_filter = xonar_d2_control_filter, | 593 | .control_filter = xonar_d2_control_filter, |
| 564 | .mixer_init = xonar_mixer_init, | 594 | .mixer_init = xonar_mixer_init, |
| 565 | .cleanup = xonar_cleanup, | 595 | .cleanup = xonar_cleanup, |
| 596 | .suspend = xonar_cleanup, | ||
| 597 | .resume = xonar_d2_resume, | ||
| 566 | .set_dac_params = set_pcm1796_params, | 598 | .set_dac_params = set_pcm1796_params, |
| 567 | .set_adc_params = set_cs53x1_params, | 599 | .set_adc_params = set_cs53x1_params, |
| 568 | .update_dac_volume = update_pcm1796_volume, | 600 | .update_dac_volume = update_pcm1796_volume, |
| @@ -592,6 +624,8 @@ static const struct oxygen_model xonar_models[] = { | |||
| 592 | .control_filter = xonar_dx_control_filter, | 624 | .control_filter = xonar_dx_control_filter, |
| 593 | .mixer_init = xonar_dx_mixer_init, | 625 | .mixer_init = xonar_dx_mixer_init, |
| 594 | .cleanup = xonar_dx_cleanup, | 626 | .cleanup = xonar_dx_cleanup, |
| 627 | .suspend = xonar_dx_cleanup, | ||
| 628 | .resume = xonar_dx_resume, | ||
| 595 | .set_dac_params = set_cs43xx_params, | 629 | .set_dac_params = set_cs43xx_params, |
| 596 | .set_adc_params = set_cs53x1_params, | 630 | .set_adc_params = set_cs53x1_params, |
| 597 | .update_dac_volume = update_cs43xx_volume, | 631 | .update_dac_volume = update_cs43xx_volume, |
| @@ -636,6 +670,10 @@ static struct pci_driver xonar_driver = { | |||
| 636 | .id_table = xonar_ids, | 670 | .id_table = xonar_ids, |
| 637 | .probe = xonar_probe, | 671 | .probe = xonar_probe, |
| 638 | .remove = __devexit_p(oxygen_pci_remove), | 672 | .remove = __devexit_p(oxygen_pci_remove), |
| 673 | #ifdef CONFIG_PM | ||
| 674 | .suspend = oxygen_pci_suspend, | ||
| 675 | .resume = oxygen_pci_resume, | ||
| 676 | #endif | ||
| 639 | }; | 677 | }; |
| 640 | 678 | ||
| 641 | static int __init alsa_card_xonar_init(void) | 679 | static int __init alsa_card_xonar_init(void) |
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 7fdcdc8c6b64..2c7e25336795 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
| @@ -516,7 +516,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) | |||
| 516 | int capture_mask = 0; | 516 | int capture_mask = 0; |
| 517 | int playback_mask = 0; | 517 | int playback_mask = 0; |
| 518 | 518 | ||
| 519 | #ifdef CONFIG_SND_DEBUG_DETECT | 519 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 520 | struct timeval my_tv1, my_tv2; | 520 | struct timeval my_tv1, my_tv2; |
| 521 | do_gettimeofday(&my_tv1); | 521 | do_gettimeofday(&my_tv1); |
| 522 | #endif | 522 | #endif |
| @@ -623,7 +623,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) | |||
| 623 | 623 | ||
| 624 | mutex_unlock(&mgr->setup_mutex); | 624 | mutex_unlock(&mgr->setup_mutex); |
| 625 | 625 | ||
| 626 | #ifdef CONFIG_SND_DEBUG_DETECT | 626 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 627 | do_gettimeofday(&my_tv2); | 627 | do_gettimeofday(&my_tv2); |
| 628 | snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", | 628 | snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", |
| 629 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); | 629 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); |
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 78aa81feaa4a..abe5c59b72df 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c | |||
| @@ -473,7 +473,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = { | |||
| 473 | [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, | 473 | [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, |
| 474 | }; | 474 | }; |
| 475 | 475 | ||
| 476 | #ifdef CONFIG_SND_DEBUG_DETECT | 476 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 477 | static char* cmd_names[] = { | 477 | static char* cmd_names[] = { |
| 478 | [CMD_VERSION] = "CMD_VERSION", | 478 | [CMD_VERSION] = "CMD_VERSION", |
| 479 | [CMD_SUPPORTED] = "CMD_SUPPORTED", | 479 | [CMD_SUPPORTED] = "CMD_SUPPORTED", |
| @@ -549,7 +549,7 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) | |||
| 549 | } | 549 | } |
| 550 | } | 550 | } |
| 551 | } | 551 | } |
| 552 | #ifdef CONFIG_SND_DEBUG_DETECT | 552 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 553 | if (rmh->cmd_idx < CMD_LAST_INDEX) | 553 | if (rmh->cmd_idx < CMD_LAST_INDEX) |
| 554 | snd_printdd(" stat[%d]=%x\n", i, data); | 554 | snd_printdd(" stat[%d]=%x\n", i, data); |
| 555 | #endif | 555 | #endif |
| @@ -597,7 +597,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) | |||
| 597 | data |= 0x008000; /* MASK_MORE_THAN_1_WORD_COMMAND */ | 597 | data |= 0x008000; /* MASK_MORE_THAN_1_WORD_COMMAND */ |
| 598 | else | 598 | else |
| 599 | data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ | 599 | data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ |
| 600 | #ifdef CONFIG_SND_DEBUG_DETECT | 600 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 601 | if (rmh->cmd_idx < CMD_LAST_INDEX) | 601 | if (rmh->cmd_idx < CMD_LAST_INDEX) |
| 602 | snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); | 602 | snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); |
| 603 | #endif | 603 | #endif |
| @@ -624,7 +624,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) | |||
| 624 | for (i=1; i < rmh->cmd_len; i++) { | 624 | for (i=1; i < rmh->cmd_len; i++) { |
| 625 | /* send other words */ | 625 | /* send other words */ |
| 626 | data = rmh->cmd[i]; | 626 | data = rmh->cmd[i]; |
| 627 | #ifdef CONFIG_SND_DEBUG_DETECT | 627 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 628 | if (rmh->cmd_idx < CMD_LAST_INDEX) | 628 | if (rmh->cmd_idx < CMD_LAST_INDEX) |
| 629 | snd_printdd(" cmd[%d]=%x\n", i, data); | 629 | snd_printdd(" cmd[%d]=%x\n", i, data); |
| 630 | #endif | 630 | #endif |
| @@ -847,7 +847,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m | |||
| 847 | int state, i, err; | 847 | int state, i, err; |
| 848 | int audio_mask; | 848 | int audio_mask; |
| 849 | 849 | ||
| 850 | #ifdef CONFIG_SND_DEBUG_DETECT | 850 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 851 | struct timeval my_tv1, my_tv2; | 851 | struct timeval my_tv1, my_tv2; |
| 852 | do_gettimeofday(&my_tv1); | 852 | do_gettimeofday(&my_tv1); |
| 853 | #endif | 853 | #endif |
| @@ -894,7 +894,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m | |||
| 894 | if (err) | 894 | if (err) |
| 895 | return err; | 895 | return err; |
| 896 | } | 896 | } |
| 897 | #ifdef CONFIG_SND_DEBUG_DETECT | 897 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 898 | do_gettimeofday(&my_tv2); | 898 | do_gettimeofday(&my_tv2); |
| 899 | snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n", | 899 | snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n", |
| 900 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); | 900 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); |
| @@ -951,7 +951,7 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, | |||
| 951 | enum pcxhr_async_err_src err_src, int pipe, | 951 | enum pcxhr_async_err_src err_src, int pipe, |
| 952 | int is_capture) | 952 | int is_capture) |
| 953 | { | 953 | { |
| 954 | #ifdef CONFIG_SND_DEBUG_DETECT | 954 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 955 | static char* err_src_name[] = { | 955 | static char* err_src_name[] = { |
| 956 | [PCXHR_ERR_PIPE] = "Pipe", | 956 | [PCXHR_ERR_PIPE] = "Pipe", |
| 957 | [PCXHR_ERR_STREAM] = "Stream", | 957 | [PCXHR_ERR_STREAM] = "Stream", |
| @@ -1169,7 +1169,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
| 1169 | mgr->dsp_time_last, dsp_time_new); | 1169 | mgr->dsp_time_last, dsp_time_new); |
| 1170 | mgr->dsp_time_err++; | 1170 | mgr->dsp_time_err++; |
| 1171 | } | 1171 | } |
| 1172 | #ifdef CONFIG_SND_DEBUG_DETECT | 1172 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 1173 | if (dsp_time_diff == 0) | 1173 | if (dsp_time_diff == 0) |
| 1174 | snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); | 1174 | snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); |
| 1175 | else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) | 1175 | else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) |
| @@ -1208,7 +1208,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
| 1208 | mgr->src_it_dsp = reg; | 1208 | mgr->src_it_dsp = reg; |
| 1209 | tasklet_hi_schedule(&mgr->msg_taskq); | 1209 | tasklet_hi_schedule(&mgr->msg_taskq); |
| 1210 | } | 1210 | } |
| 1211 | #ifdef CONFIG_SND_DEBUG_DETECT | 1211 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
| 1212 | if (reg & PCXHR_FATAL_DSP_ERR) | 1212 | if (reg & PCXHR_FATAL_DSP_ERR) |
| 1213 | snd_printdd("FATAL DSP ERROR : %x\n", reg); | 1213 | snd_printdd("FATAL DSP ERROR : %x\n", reg); |
| 1214 | #endif | 1214 | #endif |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index bbcee2c09ae4..a69b4206c69e 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
| @@ -1590,7 +1590,10 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream, | |||
| 1590 | if (spdif_flag) { | 1590 | if (spdif_flag) { |
| 1591 | if (trident->device != TRIDENT_DEVICE_ID_SI7018) { | 1591 | if (trident->device != TRIDENT_DEVICE_ID_SI7018) { |
| 1592 | outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); | 1592 | outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); |
| 1593 | outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); | 1593 | val = trident->spdif_pcm_ctrl; |
| 1594 | if (!go) | ||
| 1595 | val &= ~(0x28); | ||
| 1596 | outb(val, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); | ||
| 1594 | } else { | 1597 | } else { |
| 1595 | outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS)); | 1598 | outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS)); |
| 1596 | val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN; | 1599 | val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN; |
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index df9b487fa17e..3fd7f1b29b0f 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c | |||
| @@ -310,181 +310,3 @@ int snd_trident_free_pages(struct snd_trident *trident, | |||
| 310 | mutex_unlock(&hdr->block_mutex); | 310 | mutex_unlock(&hdr->block_mutex); |
| 311 | return 0; | 311 | return 0; |
| 312 | } | 312 | } |
| 313 | |||
| 314 | |||
| 315 | /*---------------------------------------------------------------- | ||
| 316 | * memory allocation using multiple pages (for synth) | ||
| 317 | *---------------------------------------------------------------- | ||
| 318 | * Unlike the DMA allocation above, non-contiguous pages are | ||
| 319 | * assigned to TLB. | ||
| 320 | *----------------------------------------------------------------*/ | ||
| 321 | |||
| 322 | /* | ||
| 323 | */ | ||
| 324 | static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk); | ||
| 325 | static int synth_free_pages(struct snd_trident *hw, struct snd_util_memblk *blk); | ||
| 326 | |||
| 327 | /* | ||
| 328 | * allocate a synth sample area | ||
| 329 | */ | ||
| 330 | struct snd_util_memblk * | ||
| 331 | snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size) | ||
| 332 | { | ||
| 333 | struct snd_util_memblk *blk; | ||
| 334 | struct snd_util_memhdr *hdr = hw->tlb.memhdr; | ||
| 335 | |||
| 336 | mutex_lock(&hdr->block_mutex); | ||
| 337 | blk = __snd_util_mem_alloc(hdr, size); | ||
| 338 | if (blk == NULL) { | ||
| 339 | mutex_unlock(&hdr->block_mutex); | ||
| 340 | return NULL; | ||
| 341 | } | ||
| 342 | if (synth_alloc_pages(hw, blk)) { | ||
| 343 | __snd_util_mem_free(hdr, blk); | ||
| 344 | mutex_unlock(&hdr->block_mutex); | ||
| 345 | return NULL; | ||
| 346 | } | ||
| 347 | mutex_unlock(&hdr->block_mutex); | ||
| 348 | return blk; | ||
| 349 | } | ||
| 350 | |||
| 351 | EXPORT_SYMBOL(snd_trident_synth_alloc); | ||
| 352 | |||
| 353 | /* | ||
| 354 | * free a synth sample area | ||
| 355 | */ | ||
| 356 | int | ||
| 357 | snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk) | ||
| 358 | { | ||
| 359 | struct snd_util_memhdr *hdr = hw->tlb.memhdr; | ||
| 360 | |||
| 361 | mutex_lock(&hdr->block_mutex); | ||
| 362 | synth_free_pages(hw, blk); | ||
| 363 | __snd_util_mem_free(hdr, blk); | ||
| 364 | mutex_unlock(&hdr->block_mutex); | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | EXPORT_SYMBOL(snd_trident_synth_free); | ||
| 369 | |||
| 370 | /* | ||
| 371 | * reset TLB entry and free kernel page | ||
| 372 | */ | ||
| 373 | static void clear_tlb(struct snd_trident *trident, int page) | ||
| 374 | { | ||
| 375 | void *ptr = page_to_ptr(trident, page); | ||
| 376 | dma_addr_t addr = page_to_addr(trident, page); | ||
| 377 | set_silent_tlb(trident, page); | ||
| 378 | if (ptr) { | ||
| 379 | struct snd_dma_buffer dmab; | ||
| 380 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | ||
| 381 | dmab.dev.dev = snd_dma_pci_data(trident->pci); | ||
| 382 | dmab.area = ptr; | ||
| 383 | dmab.addr = addr; | ||
| 384 | dmab.bytes = ALIGN_PAGE_SIZE; | ||
| 385 | snd_dma_free_pages(&dmab); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | /* check new allocation range */ | ||
| 390 | static void get_single_page_range(struct snd_util_memhdr *hdr, | ||
| 391 | struct snd_util_memblk *blk, | ||
| 392 | int *first_page_ret, int *last_page_ret) | ||
| 393 | { | ||
| 394 | struct list_head *p; | ||
| 395 | struct snd_util_memblk *q; | ||
| 396 | int first_page, last_page; | ||
| 397 | first_page = firstpg(blk); | ||
| 398 | if ((p = blk->list.prev) != &hdr->block) { | ||
| 399 | q = list_entry(p, struct snd_util_memblk, list); | ||
| 400 | if (lastpg(q) == first_page) | ||
| 401 | first_page++; /* first page was already allocated */ | ||
| 402 | } | ||
| 403 | last_page = lastpg(blk); | ||
| 404 | if ((p = blk->list.next) != &hdr->block) { | ||
| 405 | q = list_entry(p, struct snd_util_memblk, list); | ||
| 406 | if (firstpg(q) == last_page) | ||
| 407 | last_page--; /* last page was already allocated */ | ||
| 408 | } | ||
| 409 | *first_page_ret = first_page; | ||
| 410 | *last_page_ret = last_page; | ||
| 411 | } | ||
| 412 | |||
| 413 | /* | ||
| 414 | * allocate kernel pages and assign them to TLB | ||
| 415 | */ | ||
| 416 | static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk) | ||
| 417 | { | ||
| 418 | int page, first_page, last_page; | ||
| 419 | struct snd_dma_buffer dmab; | ||
| 420 | |||
| 421 | firstpg(blk) = get_aligned_page(blk->offset); | ||
| 422 | lastpg(blk) = get_aligned_page(blk->offset + blk->size - 1); | ||
| 423 | get_single_page_range(hw->tlb.memhdr, blk, &first_page, &last_page); | ||
| 424 | |||
| 425 | /* allocate a kernel page for each Trident page - | ||
| 426 | * fortunately Trident page size and kernel PAGE_SIZE is identical! | ||
| 427 | */ | ||
| 428 | for (page = first_page; page <= last_page; page++) { | ||
| 429 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(hw->pci), | ||
| 430 | ALIGN_PAGE_SIZE, &dmab) < 0) | ||
| 431 | goto __fail; | ||
| 432 | if (! is_valid_page(dmab.addr)) { | ||
| 433 | snd_dma_free_pages(&dmab); | ||
| 434 | goto __fail; | ||
| 435 | } | ||
| 436 | set_tlb_bus(hw, page, (unsigned long)dmab.area, dmab.addr); | ||
| 437 | } | ||
| 438 | return 0; | ||
| 439 | |||
| 440 | __fail: | ||
| 441 | /* release allocated pages */ | ||
| 442 | last_page = page - 1; | ||
| 443 | for (page = first_page; page <= last_page; page++) | ||
| 444 | clear_tlb(hw, page); | ||
| 445 | |||
| 446 | return -ENOMEM; | ||
| 447 | } | ||
| 448 | |||
| 449 | /* | ||
| 450 | * free pages | ||
| 451 | */ | ||
| 452 | static int synth_free_pages(struct snd_trident *trident, struct snd_util_memblk *blk) | ||
| 453 | { | ||
| 454 | int page, first_page, last_page; | ||
| 455 | |||
| 456 | get_single_page_range(trident->tlb.memhdr, blk, &first_page, &last_page); | ||
| 457 | for (page = first_page; page <= last_page; page++) | ||
| 458 | clear_tlb(trident, page); | ||
| 459 | |||
| 460 | return 0; | ||
| 461 | } | ||
| 462 | |||
| 463 | /* | ||
| 464 | * copy_from_user(blk + offset, data, size) | ||
| 465 | */ | ||
| 466 | int snd_trident_synth_copy_from_user(struct snd_trident *trident, | ||
| 467 | struct snd_util_memblk *blk, | ||
| 468 | int offset, const char __user *data, int size) | ||
| 469 | { | ||
| 470 | int page, nextofs, end_offset, temp, temp1; | ||
| 471 | |||
| 472 | offset += blk->offset; | ||
| 473 | end_offset = offset + size; | ||
| 474 | page = get_aligned_page(offset) + 1; | ||
| 475 | do { | ||
| 476 | nextofs = aligned_page_offset(page); | ||
| 477 | temp = nextofs - offset; | ||
| 478 | temp1 = end_offset - offset; | ||
| 479 | if (temp1 < temp) | ||
| 480 | temp = temp1; | ||
| 481 | if (copy_from_user(offset_ptr(trident, offset), data, temp)) | ||
| 482 | return -EFAULT; | ||
| 483 | offset = nextofs; | ||
| 484 | data += temp; | ||
| 485 | page++; | ||
| 486 | } while (offset < end_offset); | ||
| 487 | return 0; | ||
| 488 | } | ||
| 489 | |||
| 490 | EXPORT_SYMBOL(snd_trident_synth_copy_from_user); | ||
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index b585cc3e4c47..6781be9e3078 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
| @@ -1757,6 +1757,12 @@ static struct ac97_quirk ac97_quirks[] = { | |||
| 1757 | .type = AC97_TUNE_HP_ONLY | 1757 | .type = AC97_TUNE_HP_ONLY |
| 1758 | }, | 1758 | }, |
| 1759 | { | 1759 | { |
| 1760 | .subvendor = 0x1019, | ||
| 1761 | .subdevice = 0x1841, | ||
| 1762 | .name = "ECS K7VTA3", | ||
| 1763 | .type = AC97_TUNE_HP_ONLY | ||
| 1764 | }, | ||
| 1765 | { | ||
| 1760 | .subvendor = 0x1849, | 1766 | .subvendor = 0x1849, |
| 1761 | .subdevice = 0x3059, | 1767 | .subdevice = 0x3059, |
| 1762 | .name = "ASRock K7VM2", | 1768 | .name = "ASRock K7VM2", |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 29b3056c5109..7129df5f315b 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
| @@ -2205,6 +2205,7 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip) | |||
| 2205 | for (reg = 0x80; reg < 0xc0; reg += 4) | 2205 | for (reg = 0x80; reg < 0xc0; reg += 4) |
| 2206 | snd_ymfpci_writel(chip, reg, 0); | 2206 | snd_ymfpci_writel(chip, reg, 0); |
| 2207 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); | 2207 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); |
| 2208 | snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff); | ||
| 2208 | snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff); | 2209 | snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff); |
| 2209 | snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff); | 2210 | snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff); |
| 2210 | snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); | 2211 | snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); |
| @@ -2324,6 +2325,7 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state) | |||
| 2324 | chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); | 2325 | chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); |
| 2325 | chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); | 2326 | chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); |
| 2326 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); | 2327 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); |
| 2328 | snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); | ||
| 2327 | snd_ymfpci_disable_dsp(chip); | 2329 | snd_ymfpci_disable_dsp(chip); |
| 2328 | pci_disable_device(pci); | 2330 | pci_disable_device(pci); |
| 2329 | pci_save_state(pci); | 2331 | pci_save_state(pci); |
diff --git a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig index c9fa1a2bc58b..7fbb190adf6d 100644 --- a/sound/pcmcia/Kconfig +++ b/sound/pcmcia/Kconfig | |||
| @@ -1,11 +1,16 @@ | |||
| 1 | # ALSA PCMCIA drivers | 1 | # ALSA PCMCIA drivers |
| 2 | 2 | ||
| 3 | menu "PCMCIA devices" | 3 | menuconfig SND_PCMCIA |
| 4 | depends on SND!=n && PCMCIA | 4 | bool "PCMCIA sound devices" |
| 5 | depends on PCMCIA | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices connected via the PCMCIA bus. | ||
| 9 | |||
| 10 | if SND_PCMCIA && PCMCIA | ||
| 5 | 11 | ||
| 6 | config SND_VXPOCKET | 12 | config SND_VXPOCKET |
| 7 | tristate "Digigram VXpocket" | 13 | tristate "Digigram VXpocket" |
| 8 | depends on SND && PCMCIA | ||
| 9 | select SND_VX_LIB | 14 | select SND_VX_LIB |
| 10 | help | 15 | help |
| 11 | Say Y here to include support for Digigram VXpocket and | 16 | Say Y here to include support for Digigram VXpocket and |
| @@ -16,7 +21,6 @@ config SND_VXPOCKET | |||
| 16 | 21 | ||
| 17 | config SND_PDAUDIOCF | 22 | config SND_PDAUDIOCF |
| 18 | tristate "Sound Core PDAudioCF" | 23 | tristate "Sound Core PDAudioCF" |
| 19 | depends on SND && PCMCIA | ||
| 20 | select SND_PCM | 24 | select SND_PCM |
| 21 | help | 25 | help |
| 22 | Say Y here to include support for Sound Core PDAudioCF | 26 | Say Y here to include support for Sound Core PDAudioCF |
| @@ -25,4 +29,5 @@ config SND_PDAUDIOCF | |||
| 25 | To compile this driver as a module, choose M here: the module | 29 | To compile this driver as a module, choose M here: the module |
| 26 | will be called snd-pdaudiocf. | 30 | will be called snd-pdaudiocf. |
| 27 | 31 | ||
| 28 | endmenu | 32 | endif # SND_PCMCIA |
| 33 | |||
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 157b0b539f39..99bf2a65a6f5 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c | |||
| @@ -151,7 +151,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware * | |||
| 151 | unsigned int i; | 151 | unsigned int i; |
| 152 | int c; | 152 | int c; |
| 153 | int regCSUER, regRUER; | 153 | int regCSUER, regRUER; |
| 154 | unsigned char *image; | 154 | const unsigned char *image; |
| 155 | unsigned char data; | 155 | unsigned char data; |
| 156 | 156 | ||
| 157 | /* Switch to programmation mode */ | 157 | /* Switch to programmation mode */ |
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig index cacb0b136883..777de2b17178 100644 --- a/sound/ppc/Kconfig +++ b/sound/ppc/Kconfig | |||
| @@ -1,17 +1,17 @@ | |||
| 1 | # ALSA PowerMac drivers | 1 | # ALSA PowerMac drivers |
| 2 | 2 | ||
| 3 | menu "ALSA PowerMac devices" | 3 | menuconfig SND_PPC |
| 4 | depends on SND!=n && PPC | 4 | bool "PowerPC sound devices" |
| 5 | 5 | depends on PPC64 || PPC32 | |
| 6 | comment "ALSA PowerMac requires I2C" | 6 | default y |
| 7 | depends on SND && I2C=n | 7 | help |
| 8 | Support for sound devices specific to PowerPC architectures. | ||
| 8 | 9 | ||
| 9 | comment "ALSA PowerMac requires INPUT" | 10 | if SND_PPC |
| 10 | depends on SND && INPUT=n | ||
| 11 | 11 | ||
| 12 | config SND_POWERMAC | 12 | config SND_POWERMAC |
| 13 | tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" | 13 | tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" |
| 14 | depends on SND && I2C && INPUT && PPC_PMAC | 14 | depends on I2C && INPUT && PPC_PMAC |
| 15 | select SND_PCM | 15 | select SND_PCM |
| 16 | help | 16 | help |
| 17 | Say Y here to include support for the integrated sound device. | 17 | Say Y here to include support for the integrated sound device. |
| @@ -32,14 +32,9 @@ config SND_POWERMAC_AUTO_DRC | |||
| 32 | Note that you can turn on/off DRC manually even without this | 32 | Note that you can turn on/off DRC manually even without this |
| 33 | option. | 33 | option. |
| 34 | 34 | ||
| 35 | endmenu | ||
| 36 | |||
| 37 | menu "ALSA PowerPC devices" | ||
| 38 | depends on SND!=n && ( PPC64 || PPC32 ) | ||
| 39 | |||
| 40 | config SND_PS3 | 35 | config SND_PS3 |
| 41 | tristate "PS3 Audio support" | 36 | tristate "PS3 Audio support" |
| 42 | depends on SND && PS3_PS3AV | 37 | depends on PS3_PS3AV |
| 43 | select SND_PCM | 38 | select SND_PCM |
| 44 | default m | 39 | default m |
| 45 | help | 40 | help |
| @@ -52,4 +47,5 @@ config SND_PS3_DEFAULT_START_DELAY | |||
| 52 | int "Startup delay time in ms" | 47 | int "Startup delay time in ms" |
| 53 | depends on SND_PS3 | 48 | depends on SND_PS3 |
| 54 | default "2000" | 49 | default "2000" |
| 55 | endmenu | 50 | |
| 51 | endif # SND_PPC | ||
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index ca9452901a50..8a5b29031933 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c | |||
| @@ -249,9 +249,7 @@ int __init snd_pmac_daca_init(struct snd_pmac *chip) | |||
| 249 | int i, err; | 249 | int i, err; |
| 250 | struct pmac_daca *mix; | 250 | struct pmac_daca *mix; |
| 251 | 251 | ||
| 252 | #ifdef CONFIG_KMOD | ||
| 253 | request_module("i2c-powermac"); | 252 | request_module("i2c-powermac"); |
| 254 | #endif /* CONFIG_KMOD */ | ||
| 255 | 253 | ||
| 256 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); | 254 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); |
| 257 | if (! mix) | 255 | if (! mix) |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 3f8d7164cef9..009df8dd37a8 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
| @@ -1350,9 +1350,7 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip) | |||
| 1350 | struct device_node *tas_node, *np; | 1350 | struct device_node *tas_node, *np; |
| 1351 | char *chipname; | 1351 | char *chipname; |
| 1352 | 1352 | ||
| 1353 | #ifdef CONFIG_KMOD | ||
| 1354 | request_module("i2c-powermac"); | 1353 | request_module("i2c-powermac"); |
| 1355 | #endif /* CONFIG_KMOD */ | ||
| 1356 | 1354 | ||
| 1357 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); | 1355 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); |
| 1358 | if (! mix) | 1356 | if (! mix) |
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig index b7e08ef22a94..cfc143985802 100644 --- a/sound/sh/Kconfig +++ b/sound/sh/Kconfig | |||
| @@ -1,14 +1,22 @@ | |||
| 1 | # ALSA SH drivers | 1 | # ALSA SH drivers |
| 2 | 2 | ||
| 3 | menu "SUPERH devices" | 3 | menuconfig SND_SUPERH |
| 4 | depends on SND!=n && SUPERH | 4 | bool "SUPERH sound devices" |
| 5 | depends on SUPERH | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices specific to SUPERH architectures. | ||
| 9 | Drivers that are implemented on ASoC can be found in | ||
| 10 | "ALSA for SoC audio support" section. | ||
| 11 | |||
| 12 | if SND_SUPERH | ||
| 5 | 13 | ||
| 6 | config SND_AICA | 14 | config SND_AICA |
| 7 | tristate "Dreamcast Yamaha AICA sound" | 15 | tristate "Dreamcast Yamaha AICA sound" |
| 8 | depends on SH_DREAMCAST && SND | 16 | depends on SH_DREAMCAST |
| 9 | select SND_PCM | 17 | select SND_PCM |
| 10 | help | 18 | help |
| 11 | ALSA Sound driver for the SEGA Dreamcast console. | 19 | ALSA Sound driver for the SEGA Dreamcast console. |
| 12 | 20 | ||
| 13 | endmenu | 21 | endif # SND_SUPERH |
| 14 | 22 | ||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 18f28ac4bfe8..f743530add8f 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
| @@ -2,15 +2,8 @@ | |||
| 2 | # SoC audio configuration | 2 | # SoC audio configuration |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | menu "System on Chip audio support" | 5 | menuconfig SND_SOC |
| 6 | depends on SND!=n | ||
| 7 | |||
| 8 | config SND_SOC_AC97_BUS | ||
| 9 | bool | ||
| 10 | |||
| 11 | config SND_SOC | ||
| 12 | tristate "ALSA for SoC audio support" | 6 | tristate "ALSA for SoC audio support" |
| 13 | depends on SND | ||
| 14 | select SND_PCM | 7 | select SND_PCM |
| 15 | ---help--- | 8 | ---help--- |
| 16 | 9 | ||
| @@ -23,8 +16,15 @@ config SND_SOC | |||
| 23 | This ASoC audio support can also be built as a module. If so, the module | 16 | This ASoC audio support can also be built as a module. If so, the module |
| 24 | will be called snd-soc-core. | 17 | will be called snd-soc-core. |
| 25 | 18 | ||
| 19 | if SND_SOC | ||
| 20 | |||
| 21 | config SND_SOC_AC97_BUS | ||
| 22 | bool | ||
| 23 | |||
| 26 | # All the supported Soc's | 24 | # All the supported Soc's |
| 25 | source "sound/soc/at32/Kconfig" | ||
| 27 | source "sound/soc/at91/Kconfig" | 26 | source "sound/soc/at91/Kconfig" |
| 27 | source "sound/soc/au1x/Kconfig" | ||
| 28 | source "sound/soc/pxa/Kconfig" | 28 | source "sound/soc/pxa/Kconfig" |
| 29 | source "sound/soc/s3c24xx/Kconfig" | 29 | source "sound/soc/s3c24xx/Kconfig" |
| 30 | source "sound/soc/sh/Kconfig" | 30 | source "sound/soc/sh/Kconfig" |
| @@ -35,4 +35,5 @@ source "sound/soc/omap/Kconfig" | |||
| 35 | # Supported codecs | 35 | # Supported codecs |
| 36 | source "sound/soc/codecs/Kconfig" | 36 | source "sound/soc/codecs/Kconfig" |
| 37 | 37 | ||
| 38 | endmenu | 38 | endif # SND_SOC |
| 39 | |||
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 782db2127108..933a66d30804 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | snd-soc-core-objs := soc-core.o soc-dapm.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o |
| 2 | 2 | ||
| 3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
| 4 | obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ omap/ | 4 | obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ |
| 5 | obj-$(CONFIG_SND_SOC) += omap/ au1x/ | ||
diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig new file mode 100644 index 000000000000..b0765e86c085 --- /dev/null +++ b/sound/soc/at32/Kconfig | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | config SND_AT32_SOC | ||
| 2 | tristate "SoC Audio for the Atmel AT32 System-on-a-Chip" | ||
| 3 | depends on AVR32 && SND_SOC | ||
| 4 | help | ||
| 5 | Say Y or M if you want to add support for codecs attached to | ||
| 6 | the AT32 SSC interface. You will also need to | ||
| 7 | to select the audio interfaces to support below. | ||
| 8 | |||
| 9 | |||
| 10 | config SND_AT32_SOC_SSC | ||
| 11 | tristate | ||
| 12 | |||
| 13 | |||
| 14 | |||
| 15 | config SND_AT32_SOC_PLAYPAQ | ||
| 16 | tristate "SoC Audio support for PlayPaq with WM8510" | ||
| 17 | depends on SND_AT32_SOC && BOARD_PLAYPAQ | ||
| 18 | select SND_AT32_SOC_SSC | ||
| 19 | select SND_SOC_WM8510 | ||
| 20 | help | ||
| 21 | Say Y or M here if you want to add support for SoC audio | ||
| 22 | on the LRS PlayPaq. | ||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | config SND_AT32_SOC_PLAYPAQ_SLAVE | ||
| 27 | bool "Run CODEC on PlayPaq in slave mode" | ||
| 28 | depends on SND_AT32_SOC_PLAYPAQ | ||
| 29 | default n | ||
| 30 | help | ||
| 31 | Say Y if you want to run with the AT32 SSC generating the BCLK | ||
| 32 | and FRAME signals on the PlayPaq. Unless you want to play | ||
| 33 | with the AT32 as the SSC master, you probably want to say N here, | ||
| 34 | as this will give you better sound quality. | ||
diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile new file mode 100644 index 000000000000..c03e55ececeb --- /dev/null +++ b/sound/soc/at32/Makefile | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | # AT32 Platform Support | ||
| 2 | snd-soc-at32-objs := at32-pcm.o | ||
| 3 | snd-soc-at32-ssc-objs := at32-ssc.o | ||
| 4 | |||
| 5 | obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o | ||
| 6 | obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o | ||
| 7 | |||
| 8 | # AT32 Machine Support | ||
| 9 | snd-soc-playpaq-objs := playpaq_wm8510.o | ||
| 10 | |||
| 11 | obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o | ||
diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c new file mode 100644 index 000000000000..435f1daf177c --- /dev/null +++ b/sound/soc/at32/at32-pcm.c | |||
| @@ -0,0 +1,491 @@ | |||
| 1 | /* sound/soc/at32/at32-pcm.c | ||
| 2 | * ASoC PCM interface for Atmel AT32 SoC | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Long Range Systems | ||
| 5 | * Geoffrey Wossum <gwossum@acm.org> | ||
| 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 | * Note that this is basically a port of the sound/soc/at91-pcm.c to | ||
| 12 | * the AVR32 kernel. Thanks to Frank Mandarino for that code. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/dma-mapping.h> | ||
| 20 | #include <linux/atmel_pdc.h> | ||
| 21 | |||
| 22 | #include <sound/core.h> | ||
| 23 | #include <sound/pcm.h> | ||
| 24 | #include <sound/pcm_params.h> | ||
| 25 | #include <sound/soc.h> | ||
| 26 | |||
| 27 | #include "at32-pcm.h" | ||
| 28 | |||
| 29 | |||
| 30 | |||
| 31 | /*--------------------------------------------------------------------------*\ | ||
| 32 | * Hardware definition | ||
| 33 | \*--------------------------------------------------------------------------*/ | ||
| 34 | /* TODO: These values were taken from the AT91 platform driver, check | ||
| 35 | * them against real values for AT32 | ||
| 36 | */ | ||
| 37 | static const struct snd_pcm_hardware at32_pcm_hardware = { | ||
| 38 | .info = (SNDRV_PCM_INFO_MMAP | | ||
| 39 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 40 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 41 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
| 42 | SNDRV_PCM_INFO_PAUSE), | ||
| 43 | |||
| 44 | .formats = SNDRV_PCM_FMTBIT_S16, | ||
| 45 | .period_bytes_min = 32, | ||
| 46 | .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */ | ||
| 47 | .periods_min = 2, | ||
| 48 | .periods_max = 1024, | ||
| 49 | .buffer_bytes_max = 32 * 1024, | ||
| 50 | }; | ||
| 51 | |||
| 52 | |||
| 53 | |||
| 54 | /*--------------------------------------------------------------------------*\ | ||
| 55 | * Data types | ||
| 56 | \*--------------------------------------------------------------------------*/ | ||
| 57 | struct at32_runtime_data { | ||
| 58 | struct at32_pcm_dma_params *params; | ||
| 59 | dma_addr_t dma_buffer; /* physical address of DMA buffer */ | ||
| 60 | dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ | ||
| 61 | size_t period_size; | ||
| 62 | |||
| 63 | dma_addr_t period_ptr; /* physical address of next period */ | ||
| 64 | int periods; /* period index of period_ptr */ | ||
| 65 | |||
| 66 | /* Save PDC registers (for power management) */ | ||
| 67 | u32 pdc_xpr_save; | ||
| 68 | u32 pdc_xcr_save; | ||
| 69 | u32 pdc_xnpr_save; | ||
| 70 | u32 pdc_xncr_save; | ||
| 71 | }; | ||
| 72 | |||
| 73 | |||
| 74 | |||
| 75 | /*--------------------------------------------------------------------------*\ | ||
| 76 | * Helper functions | ||
| 77 | \*--------------------------------------------------------------------------*/ | ||
| 78 | static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
| 79 | { | ||
| 80 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
| 81 | struct snd_dma_buffer *dmabuf = &substream->dma_buffer; | ||
| 82 | size_t size = at32_pcm_hardware.buffer_bytes_max; | ||
| 83 | |||
| 84 | dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
| 85 | dmabuf->dev.dev = pcm->card->dev; | ||
| 86 | dmabuf->private_data = NULL; | ||
| 87 | dmabuf->area = dma_alloc_coherent(pcm->card->dev, size, | ||
| 88 | &dmabuf->addr, GFP_KERNEL); | ||
| 89 | pr_debug("at32_pcm: preallocate_dma_buffer: " | ||
| 90 | "area=%p, addr=%p, size=%ld\n", | ||
| 91 | (void *)dmabuf->area, (void *)dmabuf->addr, size); | ||
| 92 | |||
| 93 | if (!dmabuf->area) | ||
| 94 | return -ENOMEM; | ||
| 95 | |||
| 96 | dmabuf->bytes = size; | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | |||
| 102 | /*--------------------------------------------------------------------------*\ | ||
| 103 | * ISR | ||
| 104 | \*--------------------------------------------------------------------------*/ | ||
| 105 | static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) | ||
| 106 | { | ||
| 107 | struct snd_pcm_runtime *rtd = substream->runtime; | ||
| 108 | struct at32_runtime_data *prtd = rtd->private_data; | ||
| 109 | struct at32_pcm_dma_params *params = prtd->params; | ||
| 110 | static int count; | ||
| 111 | |||
| 112 | count++; | ||
| 113 | if (ssc_sr & params->mask->ssc_endbuf) { | ||
| 114 | pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", | ||
| 115 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
| 116 | "underrun" : "overrun", params->name, ssc_sr, count); | ||
| 117 | |||
| 118 | /* re-start the PDC */ | ||
| 119 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
| 120 | params->mask->pdc_disable); | ||
| 121 | prtd->period_ptr += prtd->period_size; | ||
| 122 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
| 123 | prtd->period_ptr = prtd->dma_buffer; | ||
| 124 | |||
| 125 | |||
| 126 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
| 127 | prtd->period_ptr); | ||
| 128 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
| 129 | prtd->period_size / params->pdc_xfer_size); | ||
| 130 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
| 131 | params->mask->pdc_enable); | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | if (ssc_sr & params->mask->ssc_endx) { | ||
| 136 | /* Load the PDC next pointer and counter registers */ | ||
| 137 | prtd->period_ptr += prtd->period_size; | ||
| 138 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
| 139 | prtd->period_ptr = prtd->dma_buffer; | ||
| 140 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
| 141 | prtd->period_ptr); | ||
| 142 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
| 143 | prtd->period_size / params->pdc_xfer_size); | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | snd_pcm_period_elapsed(substream); | ||
| 148 | } | ||
| 149 | |||
| 150 | |||
| 151 | |||
| 152 | /*--------------------------------------------------------------------------*\ | ||
| 153 | * PCM operations | ||
| 154 | \*--------------------------------------------------------------------------*/ | ||
| 155 | static int at32_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 156 | struct snd_pcm_hw_params *params) | ||
| 157 | { | ||
| 158 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 159 | struct at32_runtime_data *prtd = runtime->private_data; | ||
| 160 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 161 | |||
| 162 | /* this may get called several times by oss emulation | ||
| 163 | * with different params | ||
| 164 | */ | ||
| 165 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
| 166 | runtime->dma_bytes = params_buffer_bytes(params); | ||
| 167 | |||
| 168 | prtd->params = rtd->dai->cpu_dai->dma_data; | ||
| 169 | prtd->params->dma_intr_handler = at32_pcm_dma_irq; | ||
| 170 | |||
| 171 | prtd->dma_buffer = runtime->dma_addr; | ||
| 172 | prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; | ||
| 173 | prtd->period_size = params_period_bytes(params); | ||
| 174 | |||
| 175 | pr_debug("hw_params: DMA for %s initialized " | ||
| 176 | "(dma_bytes=%ld, period_size=%ld)\n", | ||
| 177 | prtd->params->name, runtime->dma_bytes, prtd->period_size); | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | |||
| 183 | |||
| 184 | static int at32_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 185 | { | ||
| 186 | struct at32_runtime_data *prtd = substream->runtime->private_data; | ||
| 187 | struct at32_pcm_dma_params *params = prtd->params; | ||
| 188 | |||
| 189 | if (params != NULL) { | ||
| 190 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
| 191 | params->mask->pdc_disable); | ||
| 192 | prtd->params->dma_intr_handler = NULL; | ||
| 193 | } | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | |||
| 199 | |||
| 200 | static int at32_pcm_prepare(struct snd_pcm_substream *substream) | ||
| 201 | { | ||
| 202 | struct at32_runtime_data *prtd = substream->runtime->private_data; | ||
| 203 | struct at32_pcm_dma_params *params = prtd->params; | ||
| 204 | |||
| 205 | ssc_writex(params->ssc->regs, SSC_IDR, | ||
| 206 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
| 207 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
| 208 | params->mask->pdc_disable); | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | |||
| 214 | static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 215 | { | ||
| 216 | struct snd_pcm_runtime *rtd = substream->runtime; | ||
| 217 | struct at32_runtime_data *prtd = rtd->private_data; | ||
| 218 | struct at32_pcm_dma_params *params = prtd->params; | ||
| 219 | int ret = 0; | ||
| 220 | |||
| 221 | pr_debug("at32_pcm_trigger: buffer_size = %ld, " | ||
| 222 | "dma_area = %p, dma_bytes = %ld\n", | ||
| 223 | rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); | ||
| 224 | |||
| 225 | switch (cmd) { | ||
| 226 | case SNDRV_PCM_TRIGGER_START: | ||
| 227 | prtd->period_ptr = prtd->dma_buffer; | ||
| 228 | |||
| 229 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
| 230 | prtd->period_ptr); | ||
| 231 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
| 232 | prtd->period_size / params->pdc_xfer_size); | ||
| 233 | |||
| 234 | prtd->period_ptr += prtd->period_size; | ||
| 235 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
| 236 | prtd->period_ptr); | ||
| 237 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
| 238 | prtd->period_size / params->pdc_xfer_size); | ||
| 239 | |||
| 240 | pr_debug("trigger: period_ptr=%lx, xpr=%x, " | ||
| 241 | "xcr=%d, xnpr=%x, xncr=%d\n", | ||
| 242 | (unsigned long)prtd->period_ptr, | ||
| 243 | ssc_readx(params->ssc->regs, params->pdc->xpr), | ||
| 244 | ssc_readx(params->ssc->regs, params->pdc->xcr), | ||
| 245 | ssc_readx(params->ssc->regs, params->pdc->xnpr), | ||
| 246 | ssc_readx(params->ssc->regs, params->pdc->xncr)); | ||
| 247 | |||
| 248 | ssc_writex(params->ssc->regs, SSC_IER, | ||
| 249 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
| 250 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
| 251 | params->mask->pdc_enable); | ||
| 252 | |||
| 253 | pr_debug("sr=%x, imr=%x\n", | ||
| 254 | ssc_readx(params->ssc->regs, SSC_SR), | ||
| 255 | ssc_readx(params->ssc->regs, SSC_IER)); | ||
| 256 | break; /* SNDRV_PCM_TRIGGER_START */ | ||
| 257 | |||
| 258 | |||
| 259 | |||
| 260 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 261 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 262 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 263 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
| 264 | params->mask->pdc_disable); | ||
| 265 | break; | ||
| 266 | |||
| 267 | |||
| 268 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 269 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 270 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
| 271 | params->mask->pdc_enable); | ||
| 272 | break; | ||
| 273 | |||
| 274 | default: | ||
| 275 | ret = -EINVAL; | ||
| 276 | } | ||
| 277 | |||
| 278 | return ret; | ||
| 279 | } | ||
| 280 | |||
| 281 | |||
| 282 | |||
| 283 | static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) | ||
| 284 | { | ||
| 285 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 286 | struct at32_runtime_data *prtd = runtime->private_data; | ||
| 287 | struct at32_pcm_dma_params *params = prtd->params; | ||
| 288 | dma_addr_t ptr; | ||
| 289 | snd_pcm_uframes_t x; | ||
| 290 | |||
| 291 | ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
| 292 | x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); | ||
| 293 | |||
| 294 | if (x == runtime->buffer_size) | ||
| 295 | x = 0; | ||
| 296 | |||
| 297 | return x; | ||
| 298 | } | ||
| 299 | |||
| 300 | |||
| 301 | |||
| 302 | static int at32_pcm_open(struct snd_pcm_substream *substream) | ||
| 303 | { | ||
| 304 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 305 | struct at32_runtime_data *prtd; | ||
| 306 | int ret = 0; | ||
| 307 | |||
| 308 | snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware); | ||
| 309 | |||
| 310 | /* ensure that buffer size is a multiple of period size */ | ||
| 311 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
| 312 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
| 313 | if (ret < 0) | ||
| 314 | goto out; | ||
| 315 | |||
| 316 | prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); | ||
| 317 | if (prtd == NULL) { | ||
| 318 | ret = -ENOMEM; | ||
| 319 | goto out; | ||
| 320 | } | ||
| 321 | runtime->private_data = prtd; | ||
| 322 | |||
| 323 | |||
| 324 | out: | ||
| 325 | return ret; | ||
| 326 | } | ||
| 327 | |||
| 328 | |||
| 329 | |||
| 330 | static int at32_pcm_close(struct snd_pcm_substream *substream) | ||
| 331 | { | ||
| 332 | struct at32_runtime_data *prtd = substream->runtime->private_data; | ||
| 333 | |||
| 334 | kfree(prtd); | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | static int at32_pcm_mmap(struct snd_pcm_substream *substream, | ||
| 340 | struct vm_area_struct *vma) | ||
| 341 | { | ||
| 342 | return remap_pfn_range(vma, vma->vm_start, | ||
| 343 | substream->dma_buffer.addr >> PAGE_SHIFT, | ||
| 344 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
| 345 | } | ||
| 346 | |||
| 347 | |||
| 348 | |||
| 349 | static struct snd_pcm_ops at32_pcm_ops = { | ||
| 350 | .open = at32_pcm_open, | ||
| 351 | .close = at32_pcm_close, | ||
| 352 | .ioctl = snd_pcm_lib_ioctl, | ||
| 353 | .hw_params = at32_pcm_hw_params, | ||
| 354 | .hw_free = at32_pcm_hw_free, | ||
| 355 | .prepare = at32_pcm_prepare, | ||
| 356 | .trigger = at32_pcm_trigger, | ||
| 357 | .pointer = at32_pcm_pointer, | ||
| 358 | .mmap = at32_pcm_mmap, | ||
| 359 | }; | ||
| 360 | |||
| 361 | |||
| 362 | |||
| 363 | /*--------------------------------------------------------------------------*\ | ||
| 364 | * ASoC platform driver | ||
| 365 | \*--------------------------------------------------------------------------*/ | ||
| 366 | static u64 at32_pcm_dmamask = 0xffffffff; | ||
| 367 | |||
| 368 | static int at32_pcm_new(struct snd_card *card, | ||
| 369 | struct snd_soc_dai *dai, | ||
| 370 | struct snd_pcm *pcm) | ||
| 371 | { | ||
| 372 | int ret = 0; | ||
| 373 | |||
| 374 | if (!card->dev->dma_mask) | ||
| 375 | card->dev->dma_mask = &at32_pcm_dmamask; | ||
| 376 | if (!card->dev->coherent_dma_mask) | ||
| 377 | card->dev->coherent_dma_mask = 0xffffffff; | ||
| 378 | |||
| 379 | if (dai->playback.channels_min) { | ||
| 380 | ret = at32_pcm_preallocate_dma_buffer( | ||
| 381 | pcm, SNDRV_PCM_STREAM_PLAYBACK); | ||
| 382 | if (ret) | ||
| 383 | goto out; | ||
| 384 | } | ||
| 385 | |||
| 386 | if (dai->capture.channels_min) { | ||
| 387 | pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n"); | ||
| 388 | ret = at32_pcm_preallocate_dma_buffer( | ||
| 389 | pcm, SNDRV_PCM_STREAM_CAPTURE); | ||
| 390 | if (ret) | ||
| 391 | goto out; | ||
| 392 | } | ||
| 393 | |||
| 394 | |||
| 395 | out: | ||
| 396 | return ret; | ||
| 397 | } | ||
| 398 | |||
| 399 | |||
| 400 | |||
| 401 | static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
| 402 | { | ||
| 403 | struct snd_pcm_substream *substream; | ||
| 404 | struct snd_dma_buffer *buf; | ||
| 405 | int stream; | ||
| 406 | |||
| 407 | for (stream = 0; stream < 2; stream++) { | ||
| 408 | substream = pcm->streams[stream].substream; | ||
| 409 | if (substream == NULL) | ||
| 410 | continue; | ||
| 411 | |||
| 412 | buf = &substream->dma_buffer; | ||
| 413 | if (!buf->area) | ||
| 414 | continue; | ||
| 415 | dma_free_coherent(pcm->card->dev, buf->bytes, | ||
| 416 | buf->area, buf->addr); | ||
| 417 | buf->area = NULL; | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | |||
| 422 | |||
| 423 | #ifdef CONFIG_PM | ||
| 424 | static int at32_pcm_suspend(struct platform_device *pdev, | ||
| 425 | struct snd_soc_dai *dai) | ||
| 426 | { | ||
| 427 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
| 428 | struct at32_runtime_data *prtd; | ||
| 429 | struct at32_pcm_dma_params *params; | ||
| 430 | |||
| 431 | if (runtime == NULL) | ||
| 432 | return 0; | ||
| 433 | prtd = runtime->private_data; | ||
| 434 | params = prtd->params; | ||
| 435 | |||
| 436 | /* Disable the PDC and save the PDC registers */ | ||
| 437 | ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); | ||
| 438 | |||
| 439 | prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
| 440 | prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); | ||
| 441 | prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); | ||
| 442 | prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); | ||
| 443 | |||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | |||
| 447 | |||
| 448 | |||
| 449 | static int at32_pcm_resume(struct platform_device *pdev, | ||
| 450 | struct snd_soc_dai *dai) | ||
| 451 | { | ||
| 452 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
| 453 | struct at32_runtime_data *prtd; | ||
| 454 | struct at32_pcm_dma_params *params; | ||
| 455 | |||
| 456 | if (runtime == NULL) | ||
| 457 | return 0; | ||
| 458 | prtd = runtime->private_data; | ||
| 459 | params = prtd->params; | ||
| 460 | |||
| 461 | /* Restore the PDC registers and enable the PDC */ | ||
| 462 | ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); | ||
| 463 | ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); | ||
| 464 | ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); | ||
| 465 | ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); | ||
| 466 | |||
| 467 | ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); | ||
| 468 | return 0; | ||
| 469 | } | ||
| 470 | #else /* CONFIG_PM */ | ||
| 471 | # define at32_pcm_suspend NULL | ||
| 472 | # define at32_pcm_resume NULL | ||
| 473 | #endif /* CONFIG_PM */ | ||
| 474 | |||
| 475 | |||
| 476 | |||
| 477 | struct snd_soc_platform at32_soc_platform = { | ||
| 478 | .name = "at32-audio", | ||
| 479 | .pcm_ops = &at32_pcm_ops, | ||
| 480 | .pcm_new = at32_pcm_new, | ||
| 481 | .pcm_free = at32_pcm_free_dma_buffers, | ||
| 482 | .suspend = at32_pcm_suspend, | ||
| 483 | .resume = at32_pcm_resume, | ||
| 484 | }; | ||
| 485 | EXPORT_SYMBOL_GPL(at32_soc_platform); | ||
| 486 | |||
| 487 | |||
| 488 | |||
| 489 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | ||
| 490 | MODULE_DESCRIPTION("Atmel AT32 PCM module"); | ||
| 491 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h new file mode 100644 index 000000000000..2a52430417da --- /dev/null +++ b/sound/soc/at32/at32-pcm.h | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* sound/soc/at32/at32-pcm.h | ||
| 2 | * ASoC PCM interface for Atmel AT32 SoC | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Long Range Systems | ||
| 5 | * Geoffrey Wossum <gwossum@acm.org> | ||
| 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 __SOUND_SOC_AT32_AT32_PCM_H | ||
| 13 | #define __SOUND_SOC_AT32_AT32_PCM_H __FILE__ | ||
| 14 | |||
| 15 | #include <linux/atmel-ssc.h> | ||
| 16 | |||
| 17 | |||
| 18 | /* | ||
| 19 | * Registers and status bits that are required by the PCM driver | ||
| 20 | * TODO: Is ptcr really used? | ||
| 21 | */ | ||
| 22 | struct at32_pdc_regs { | ||
| 23 | u32 xpr; /* PDC RX/TX pointer */ | ||
| 24 | u32 xcr; /* PDC RX/TX counter */ | ||
| 25 | u32 xnpr; /* PDC next RX/TX pointer */ | ||
| 26 | u32 xncr; /* PDC next RX/TX counter */ | ||
| 27 | u32 ptcr; /* PDC transfer control */ | ||
| 28 | }; | ||
| 29 | |||
| 30 | |||
| 31 | |||
| 32 | /* | ||
| 33 | * SSC mask info | ||
| 34 | */ | ||
| 35 | struct at32_ssc_mask { | ||
| 36 | u32 ssc_enable; /* SSC RX/TX enable */ | ||
| 37 | u32 ssc_disable; /* SSC RX/TX disable */ | ||
| 38 | u32 ssc_endx; /* SSC ENDTX or ENDRX */ | ||
| 39 | u32 ssc_endbuf; /* SSC TXBUFF or RXBUFF */ | ||
| 40 | u32 pdc_enable; /* PDC RX/TX enable */ | ||
| 41 | u32 pdc_disable; /* PDC RX/TX disable */ | ||
| 42 | }; | ||
| 43 | |||
| 44 | |||
| 45 | |||
| 46 | /* | ||
| 47 | * This structure, shared between the PCM driver and the interface, | ||
| 48 | * contains all information required by the PCM driver to perform the | ||
| 49 | * PDC DMA operation. All fields except dma_intr_handler() are initialized | ||
| 50 | * by the interface. The dms_intr_handler() pointer is set by the PCM | ||
| 51 | * driver and called by the interface SSC interrupt handler if it is | ||
| 52 | * non-NULL. | ||
| 53 | */ | ||
| 54 | struct at32_pcm_dma_params { | ||
| 55 | char *name; /* stream identifier */ | ||
| 56 | int pdc_xfer_size; /* PDC counter increment in bytes */ | ||
| 57 | struct ssc_device *ssc; /* SSC device for stream */ | ||
| 58 | struct at32_pdc_regs *pdc; /* PDC register info */ | ||
| 59 | struct at32_ssc_mask *mask; /* SSC mask info */ | ||
| 60 | struct snd_pcm_substream *substream; | ||
| 61 | void (*dma_intr_handler) (u32, struct snd_pcm_substream *); | ||
| 62 | }; | ||
| 63 | |||
| 64 | |||
| 65 | |||
| 66 | /* | ||
| 67 | * The AT32 ASoC platform driver | ||
| 68 | */ | ||
| 69 | extern struct snd_soc_platform at32_soc_platform; | ||
| 70 | |||
| 71 | |||
| 72 | |||
| 73 | /* | ||
| 74 | * SSC register access (since ssc_writel() / ssc_readl() require literal name) | ||
| 75 | */ | ||
| 76 | #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) | ||
| 77 | #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) | ||
| 78 | |||
| 79 | #endif /* __SOUND_SOC_AT32_AT32_PCM_H */ | ||
diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c new file mode 100644 index 000000000000..4ef6492c902e --- /dev/null +++ b/sound/soc/at32/at32-ssc.c | |||
| @@ -0,0 +1,849 @@ | |||
| 1 | /* sound/soc/at32/at32-ssc.c | ||
| 2 | * ASoC platform driver for AT32 using SSC as DAI | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Long Range Systems | ||
| 5 | * Geoffrey Wossum <gwossum@acm.org> | ||
| 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 | * Note that this is basically a port of the sound/soc/at91-ssc.c to | ||
| 12 | * the AVR32 kernel. Thanks to Frank Mandarino for that code. | ||
| 13 | */ | ||
| 14 | |||
| 15 | /* #define DEBUG */ | ||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/device.h> | ||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/clk.h> | ||
| 23 | #include <linux/io.h> | ||
| 24 | #include <linux/atmel_pdc.h> | ||
| 25 | #include <linux/atmel-ssc.h> | ||
| 26 | |||
| 27 | #include <sound/core.h> | ||
| 28 | #include <sound/pcm.h> | ||
| 29 | #include <sound/pcm_params.h> | ||
| 30 | #include <sound/initval.h> | ||
| 31 | #include <sound/soc.h> | ||
| 32 | |||
| 33 | #include "at32-pcm.h" | ||
| 34 | #include "at32-ssc.h" | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /*-------------------------------------------------------------------------*\ | ||
| 39 | * Constants | ||
| 40 | \*-------------------------------------------------------------------------*/ | ||
| 41 | #define NUM_SSC_DEVICES 3 | ||
| 42 | |||
| 43 | /* | ||
| 44 | * SSC direction masks | ||
| 45 | */ | ||
| 46 | #define SSC_DIR_MASK_UNUSED 0 | ||
| 47 | #define SSC_DIR_MASK_PLAYBACK 1 | ||
| 48 | #define SSC_DIR_MASK_CAPTURE 2 | ||
| 49 | |||
| 50 | /* | ||
| 51 | * SSC register values that Atmel left out of <linux/atmel-ssc.h>. These | ||
| 52 | * are expected to be used with SSC_BF | ||
| 53 | */ | ||
| 54 | /* START bit field values */ | ||
| 55 | #define SSC_START_CONTINUOUS 0 | ||
| 56 | #define SSC_START_TX_RX 1 | ||
| 57 | #define SSC_START_LOW_RF 2 | ||
| 58 | #define SSC_START_HIGH_RF 3 | ||
| 59 | #define SSC_START_FALLING_RF 4 | ||
| 60 | #define SSC_START_RISING_RF 5 | ||
| 61 | #define SSC_START_LEVEL_RF 6 | ||
| 62 | #define SSC_START_EDGE_RF 7 | ||
| 63 | #define SSS_START_COMPARE_0 8 | ||
| 64 | |||
| 65 | /* CKI bit field values */ | ||
| 66 | #define SSC_CKI_FALLING 0 | ||
| 67 | #define SSC_CKI_RISING 1 | ||
| 68 | |||
| 69 | /* CKO bit field values */ | ||
| 70 | #define SSC_CKO_NONE 0 | ||
| 71 | #define SSC_CKO_CONTINUOUS 1 | ||
| 72 | #define SSC_CKO_TRANSFER 2 | ||
| 73 | |||
| 74 | /* CKS bit field values */ | ||
| 75 | #define SSC_CKS_DIV 0 | ||
| 76 | #define SSC_CKS_CLOCK 1 | ||
| 77 | #define SSC_CKS_PIN 2 | ||
| 78 | |||
| 79 | /* FSEDGE bit field values */ | ||
| 80 | #define SSC_FSEDGE_POSITIVE 0 | ||
| 81 | #define SSC_FSEDGE_NEGATIVE 1 | ||
| 82 | |||
| 83 | /* FSOS bit field values */ | ||
| 84 | #define SSC_FSOS_NONE 0 | ||
| 85 | #define SSC_FSOS_NEGATIVE 1 | ||
| 86 | #define SSC_FSOS_POSITIVE 2 | ||
| 87 | #define SSC_FSOS_LOW 3 | ||
| 88 | #define SSC_FSOS_HIGH 4 | ||
| 89 | #define SSC_FSOS_TOGGLE 5 | ||
| 90 | |||
| 91 | #define START_DELAY 1 | ||
| 92 | |||
| 93 | |||
| 94 | |||
| 95 | /*-------------------------------------------------------------------------*\ | ||
| 96 | * Module data | ||
| 97 | \*-------------------------------------------------------------------------*/ | ||
| 98 | /* | ||
| 99 | * SSC PDC registered required by the PCM DMA engine | ||
| 100 | */ | ||
| 101 | static struct at32_pdc_regs pdc_tx_reg = { | ||
| 102 | .xpr = SSC_PDC_TPR, | ||
| 103 | .xcr = SSC_PDC_TCR, | ||
| 104 | .xnpr = SSC_PDC_TNPR, | ||
| 105 | .xncr = SSC_PDC_TNCR, | ||
| 106 | }; | ||
| 107 | |||
| 108 | |||
| 109 | |||
| 110 | static struct at32_pdc_regs pdc_rx_reg = { | ||
| 111 | .xpr = SSC_PDC_RPR, | ||
| 112 | .xcr = SSC_PDC_RCR, | ||
| 113 | .xnpr = SSC_PDC_RNPR, | ||
| 114 | .xncr = SSC_PDC_RNCR, | ||
| 115 | }; | ||
| 116 | |||
| 117 | |||
| 118 | |||
| 119 | /* | ||
| 120 | * SSC and PDC status bits for transmit and receive | ||
| 121 | */ | ||
| 122 | static struct at32_ssc_mask ssc_tx_mask = { | ||
| 123 | .ssc_enable = SSC_BIT(CR_TXEN), | ||
| 124 | .ssc_disable = SSC_BIT(CR_TXDIS), | ||
| 125 | .ssc_endx = SSC_BIT(SR_ENDTX), | ||
| 126 | .ssc_endbuf = SSC_BIT(SR_TXBUFE), | ||
| 127 | .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN), | ||
| 128 | .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS), | ||
| 129 | }; | ||
| 130 | |||
| 131 | |||
| 132 | |||
| 133 | static struct at32_ssc_mask ssc_rx_mask = { | ||
| 134 | .ssc_enable = SSC_BIT(CR_RXEN), | ||
| 135 | .ssc_disable = SSC_BIT(CR_RXDIS), | ||
| 136 | .ssc_endx = SSC_BIT(SR_ENDRX), | ||
| 137 | .ssc_endbuf = SSC_BIT(SR_RXBUFF), | ||
| 138 | .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN), | ||
| 139 | .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS), | ||
| 140 | }; | ||
| 141 | |||
| 142 | |||
| 143 | |||
| 144 | /* | ||
| 145 | * DMA parameters for each SSC | ||
| 146 | */ | ||
| 147 | static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { | ||
| 148 | { | ||
| 149 | { | ||
| 150 | .name = "SSC0 PCM out", | ||
| 151 | .pdc = &pdc_tx_reg, | ||
| 152 | .mask = &ssc_tx_mask, | ||
| 153 | }, | ||
| 154 | { | ||
| 155 | .name = "SSC0 PCM in", | ||
| 156 | .pdc = &pdc_rx_reg, | ||
| 157 | .mask = &ssc_rx_mask, | ||
| 158 | }, | ||
| 159 | }, | ||
| 160 | { | ||
| 161 | { | ||
| 162 | .name = "SSC1 PCM out", | ||
| 163 | .pdc = &pdc_tx_reg, | ||
| 164 | .mask = &ssc_tx_mask, | ||
| 165 | }, | ||
| 166 | { | ||
| 167 | .name = "SSC1 PCM in", | ||
| 168 | .pdc = &pdc_rx_reg, | ||
| 169 | .mask = &ssc_rx_mask, | ||
| 170 | }, | ||
| 171 | }, | ||
| 172 | { | ||
| 173 | { | ||
| 174 | .name = "SSC2 PCM out", | ||
| 175 | .pdc = &pdc_tx_reg, | ||
| 176 | .mask = &ssc_tx_mask, | ||
| 177 | }, | ||
| 178 | { | ||
| 179 | .name = "SSC2 PCM in", | ||
| 180 | .pdc = &pdc_rx_reg, | ||
| 181 | .mask = &ssc_rx_mask, | ||
| 182 | }, | ||
| 183 | }, | ||
| 184 | }; | ||
| 185 | |||
| 186 | |||
| 187 | |||
| 188 | static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = { | ||
| 189 | { | ||
| 190 | .name = "ssc0", | ||
| 191 | .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), | ||
| 192 | .dir_mask = SSC_DIR_MASK_UNUSED, | ||
| 193 | .initialized = 0, | ||
| 194 | }, | ||
| 195 | { | ||
| 196 | .name = "ssc1", | ||
| 197 | .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), | ||
| 198 | .dir_mask = SSC_DIR_MASK_UNUSED, | ||
| 199 | .initialized = 0, | ||
| 200 | }, | ||
| 201 | { | ||
| 202 | .name = "ssc2", | ||
| 203 | .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), | ||
| 204 | .dir_mask = SSC_DIR_MASK_UNUSED, | ||
| 205 | .initialized = 0, | ||
| 206 | }, | ||
| 207 | }; | ||
| 208 | |||
| 209 | |||
| 210 | |||
| 211 | |||
| 212 | /*-------------------------------------------------------------------------*\ | ||
| 213 | * ISR | ||
| 214 | \*-------------------------------------------------------------------------*/ | ||
| 215 | /* | ||
| 216 | * SSC interrupt handler. Passes PDC interrupts to the DMA interrupt | ||
| 217 | * handler in the PCM driver. | ||
| 218 | */ | ||
| 219 | static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id) | ||
| 220 | { | ||
| 221 | struct at32_ssc_info *ssc_p = dev_id; | ||
| 222 | struct at32_pcm_dma_params *dma_params; | ||
| 223 | u32 ssc_sr; | ||
| 224 | u32 ssc_substream_mask; | ||
| 225 | int i; | ||
| 226 | |||
| 227 | ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) & | ||
| 228 | ssc_readl(ssc_p->ssc->regs, IMR)); | ||
| 229 | |||
| 230 | /* | ||
| 231 | * Loop through substreams attached to this SSC. If a DMA-related | ||
| 232 | * interrupt occured on that substream, call the DMA interrupt | ||
| 233 | * handler function, if one has been registered in the dma_param | ||
| 234 | * structure by the PCM driver. | ||
| 235 | */ | ||
| 236 | for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { | ||
| 237 | dma_params = ssc_p->dma_params[i]; | ||
| 238 | |||
| 239 | if ((dma_params != NULL) && | ||
| 240 | (dma_params->dma_intr_handler != NULL)) { | ||
| 241 | ssc_substream_mask = (dma_params->mask->ssc_endx | | ||
| 242 | dma_params->mask->ssc_endbuf); | ||
| 243 | if (ssc_sr & ssc_substream_mask) { | ||
| 244 | dma_params->dma_intr_handler(ssc_sr, | ||
| 245 | dma_params-> | ||
| 246 | substream); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | |||
| 252 | return IRQ_HANDLED; | ||
| 253 | } | ||
| 254 | |||
| 255 | /*-------------------------------------------------------------------------*\ | ||
| 256 | * DAI functions | ||
| 257 | \*-------------------------------------------------------------------------*/ | ||
| 258 | /* | ||
| 259 | * Startup. Only that one substream allowed in each direction. | ||
| 260 | */ | ||
| 261 | static int at32_ssc_startup(struct snd_pcm_substream *substream) | ||
| 262 | { | ||
| 263 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 264 | struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
| 265 | int dir_mask; | ||
| 266 | |||
| 267 | dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
| 268 | SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE); | ||
| 269 | |||
| 270 | spin_lock_irq(&ssc_p->lock); | ||
| 271 | if (ssc_p->dir_mask & dir_mask) { | ||
| 272 | spin_unlock_irq(&ssc_p->lock); | ||
| 273 | return -EBUSY; | ||
| 274 | } | ||
| 275 | ssc_p->dir_mask |= dir_mask; | ||
| 276 | spin_unlock_irq(&ssc_p->lock); | ||
| 277 | |||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | |||
| 282 | |||
| 283 | /* | ||
| 284 | * Shutdown. Clear DMA parameters and shutdown the SSC if there | ||
| 285 | * are no other substreams open. | ||
| 286 | */ | ||
| 287 | static void at32_ssc_shutdown(struct snd_pcm_substream *substream) | ||
| 288 | { | ||
| 289 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 290 | struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
| 291 | struct at32_pcm_dma_params *dma_params; | ||
| 292 | int dir_mask; | ||
| 293 | |||
| 294 | dma_params = ssc_p->dma_params[substream->stream]; | ||
| 295 | |||
| 296 | if (dma_params != NULL) { | ||
| 297 | ssc_writel(dma_params->ssc->regs, CR, | ||
| 298 | dma_params->mask->ssc_disable); | ||
| 299 | pr_debug("%s disabled SSC_SR=0x%08x\n", | ||
| 300 | (substream->stream ? "receiver" : "transmit"), | ||
| 301 | ssc_readl(ssc_p->ssc->regs, SR)); | ||
| 302 | |||
| 303 | dma_params->ssc = NULL; | ||
| 304 | dma_params->substream = NULL; | ||
| 305 | ssc_p->dma_params[substream->stream] = NULL; | ||
| 306 | } | ||
| 307 | |||
| 308 | |||
| 309 | dir_mask = 1 << substream->stream; | ||
| 310 | spin_lock_irq(&ssc_p->lock); | ||
| 311 | ssc_p->dir_mask &= ~dir_mask; | ||
| 312 | if (!ssc_p->dir_mask) { | ||
| 313 | /* Shutdown the SSC clock */ | ||
| 314 | pr_debug("at32-ssc: Stopping user %d clock\n", | ||
| 315 | ssc_p->ssc->user); | ||
| 316 | clk_disable(ssc_p->ssc->clk); | ||
| 317 | |||
| 318 | if (ssc_p->initialized) { | ||
| 319 | free_irq(ssc_p->ssc->irq, ssc_p); | ||
| 320 | ssc_p->initialized = 0; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* Reset the SSC */ | ||
| 324 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); | ||
| 325 | |||
| 326 | /* clear the SSC dividers */ | ||
| 327 | ssc_p->cmr_div = 0; | ||
| 328 | ssc_p->tcmr_period = 0; | ||
| 329 | ssc_p->rcmr_period = 0; | ||
| 330 | } | ||
| 331 | spin_unlock_irq(&ssc_p->lock); | ||
| 332 | } | ||
| 333 | |||
| 334 | |||
| 335 | |||
| 336 | /* | ||
| 337 | * Set the SSC system clock rate | ||
| 338 | */ | ||
| 339 | static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | ||
| 340 | int clk_id, unsigned int freq, int dir) | ||
| 341 | { | ||
| 342 | /* TODO: What the heck do I do here? */ | ||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | |||
| 347 | |||
| 348 | /* | ||
| 349 | * Record DAI format for use by hw_params() | ||
| 350 | */ | ||
| 351 | static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
| 352 | unsigned int fmt) | ||
| 353 | { | ||
| 354 | struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | ||
| 355 | |||
| 356 | ssc_p->daifmt = fmt; | ||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | |||
| 361 | |||
| 362 | /* | ||
| 363 | * Record SSC clock dividers for use in hw_params() | ||
| 364 | */ | ||
| 365 | static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | ||
| 366 | int div_id, int div) | ||
| 367 | { | ||
| 368 | struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | ||
| 369 | |||
| 370 | switch (div_id) { | ||
| 371 | case AT32_SSC_CMR_DIV: | ||
| 372 | /* | ||
| 373 | * The same master clock divider is used for both | ||
| 374 | * transmit and receive, so if a value has already | ||
| 375 | * been set, it must match this value | ||
| 376 | */ | ||
| 377 | if (ssc_p->cmr_div == 0) | ||
| 378 | ssc_p->cmr_div = div; | ||
| 379 | else if (div != ssc_p->cmr_div) | ||
| 380 | return -EBUSY; | ||
| 381 | break; | ||
| 382 | |||
| 383 | case AT32_SSC_TCMR_PERIOD: | ||
| 384 | ssc_p->tcmr_period = div; | ||
| 385 | break; | ||
| 386 | |||
| 387 | case AT32_SSC_RCMR_PERIOD: | ||
| 388 | ssc_p->rcmr_period = div; | ||
| 389 | break; | ||
| 390 | |||
| 391 | default: | ||
| 392 | return -EINVAL; | ||
| 393 | } | ||
| 394 | |||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | |||
| 398 | |||
| 399 | |||
| 400 | /* | ||
| 401 | * Configure the SSC | ||
| 402 | */ | ||
| 403 | static int at32_ssc_hw_params(struct snd_pcm_substream *substream, | ||
| 404 | struct snd_pcm_hw_params *params) | ||
| 405 | { | ||
| 406 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 407 | int id = rtd->dai->cpu_dai->id; | ||
| 408 | struct at32_ssc_info *ssc_p = &ssc_info[id]; | ||
| 409 | struct at32_pcm_dma_params *dma_params; | ||
| 410 | int channels, bits; | ||
| 411 | u32 tfmr, rfmr, tcmr, rcmr; | ||
| 412 | int start_event; | ||
| 413 | int ret; | ||
| 414 | |||
| 415 | |||
| 416 | /* | ||
| 417 | * Currently, there is only one set of dma_params for each direction. | ||
| 418 | * If more are added, this code will have to be changed to select | ||
| 419 | * the proper set | ||
| 420 | */ | ||
| 421 | dma_params = &ssc_dma_params[id][substream->stream]; | ||
| 422 | dma_params->ssc = ssc_p->ssc; | ||
| 423 | dma_params->substream = substream; | ||
| 424 | |||
| 425 | ssc_p->dma_params[substream->stream] = dma_params; | ||
| 426 | |||
| 427 | |||
| 428 | /* | ||
| 429 | * The cpu_dai->dma_data field is only used to communicate the | ||
| 430 | * appropriate DMA parameters to the PCM driver's hw_params() | ||
| 431 | * function. It should not be used for other purposes as it | ||
| 432 | * is common to all substreams. | ||
| 433 | */ | ||
| 434 | rtd->dai->cpu_dai->dma_data = dma_params; | ||
| 435 | |||
| 436 | channels = params_channels(params); | ||
| 437 | |||
| 438 | |||
| 439 | /* | ||
| 440 | * Determine sample size in bits and the PDC increment | ||
| 441 | */ | ||
| 442 | switch (params_format(params)) { | ||
| 443 | case SNDRV_PCM_FORMAT_S8: | ||
| 444 | bits = 8; | ||
| 445 | dma_params->pdc_xfer_size = 1; | ||
| 446 | break; | ||
| 447 | |||
| 448 | case SNDRV_PCM_FORMAT_S16: | ||
| 449 | bits = 16; | ||
| 450 | dma_params->pdc_xfer_size = 2; | ||
| 451 | break; | ||
| 452 | |||
| 453 | case SNDRV_PCM_FORMAT_S24: | ||
| 454 | bits = 24; | ||
| 455 | dma_params->pdc_xfer_size = 4; | ||
| 456 | break; | ||
| 457 | |||
| 458 | case SNDRV_PCM_FORMAT_S32: | ||
| 459 | bits = 32; | ||
| 460 | dma_params->pdc_xfer_size = 4; | ||
| 461 | break; | ||
| 462 | |||
| 463 | default: | ||
| 464 | pr_warning("at32-ssc: Unsupported PCM format %d", | ||
| 465 | params_format(params)); | ||
| 466 | return -EINVAL; | ||
| 467 | } | ||
| 468 | pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", | ||
| 469 | bits, dma_params->pdc_xfer_size, channels); | ||
| 470 | |||
| 471 | |||
| 472 | /* | ||
| 473 | * The SSC only supports up to 16-bit samples in I2S format, due | ||
| 474 | * to the size of the Frame Mode Register FSLEN field. | ||
| 475 | */ | ||
| 476 | if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) | ||
| 477 | if (bits > 16) { | ||
| 478 | pr_warning("at32-ssc: " | ||
| 479 | "sample size %d is too large for I2S\n", | ||
| 480 | bits); | ||
| 481 | return -EINVAL; | ||
| 482 | } | ||
| 483 | |||
| 484 | |||
| 485 | /* | ||
| 486 | * Compute the SSC register settings | ||
| 487 | */ | ||
| 488 | switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | | ||
| 489 | SND_SOC_DAIFMT_MASTER_MASK)) { | ||
| 490 | case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: | ||
| 491 | /* | ||
| 492 | * I2S format, SSC provides BCLK and LRS clocks. | ||
| 493 | * | ||
| 494 | * The SSC transmit and receive clocks are generated from the | ||
| 495 | * MCK divider, and the BCLK signal is output on the SSC TK line | ||
| 496 | */ | ||
| 497 | pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); | ||
| 498 | rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | | ||
| 499 | SSC_BF(RCMR_STTDLY, START_DELAY) | | ||
| 500 | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | | ||
| 501 | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | | ||
| 502 | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | | ||
| 503 | SSC_BF(RCMR_CKS, SSC_CKS_DIV)); | ||
| 504 | |||
| 505 | rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
| 506 | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | | ||
| 507 | SSC_BF(RFMR_FSLEN, bits - 1) | | ||
| 508 | SSC_BF(RFMR_DATNB, channels - 1) | | ||
| 509 | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); | ||
| 510 | |||
| 511 | tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | | ||
| 512 | SSC_BF(TCMR_STTDLY, START_DELAY) | | ||
| 513 | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | | ||
| 514 | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | | ||
| 515 | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | | ||
| 516 | SSC_BF(TCMR_CKS, SSC_CKS_DIV)); | ||
| 517 | |||
| 518 | tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
| 519 | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | | ||
| 520 | SSC_BF(TFMR_FSLEN, bits - 1) | | ||
| 521 | SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | | ||
| 522 | SSC_BF(TFMR_DATLEN, bits - 1)); | ||
| 523 | break; | ||
| 524 | |||
| 525 | |||
| 526 | case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: | ||
| 527 | /* | ||
| 528 | * I2S format, CODEC supplies BCLK and LRC clock. | ||
| 529 | * | ||
| 530 | * The SSC transmit clock is obtained from the BCLK signal | ||
| 531 | * on the TK line, and the SSC receive clock is generated from | ||
| 532 | * the transmit clock. | ||
| 533 | * | ||
| 534 | * For single channel data, one sample is transferred on the | ||
| 535 | * falling edge of the LRC clock. For two channel data, one | ||
| 536 | * sample is transferred on both edges of the LRC clock. | ||
| 537 | */ | ||
| 538 | pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); | ||
| 539 | start_event = ((channels == 1) ? | ||
| 540 | SSC_START_FALLING_RF : SSC_START_EDGE_RF); | ||
| 541 | |||
| 542 | rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | | ||
| 543 | SSC_BF(RCMR_START, start_event) | | ||
| 544 | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | | ||
| 545 | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | | ||
| 546 | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK)); | ||
| 547 | |||
| 548 | rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
| 549 | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | | ||
| 550 | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); | ||
| 551 | |||
| 552 | tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | | ||
| 553 | SSC_BF(TCMR_START, start_event) | | ||
| 554 | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | | ||
| 555 | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | | ||
| 556 | SSC_BF(TCMR_CKS, SSC_CKS_PIN)); | ||
| 557 | |||
| 558 | tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
| 559 | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | | ||
| 560 | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); | ||
| 561 | break; | ||
| 562 | |||
| 563 | |||
| 564 | case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: | ||
| 565 | /* | ||
| 566 | * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. | ||
| 567 | * | ||
| 568 | * The SSC transmit and receive clocks are generated from the | ||
| 569 | * MCK divider, and the BCLK signal is output on the SSC TK line | ||
| 570 | */ | ||
| 571 | pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); | ||
| 572 | rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | | ||
| 573 | SSC_BF(RCMR_STTDLY, 1) | | ||
| 574 | SSC_BF(RCMR_START, SSC_START_RISING_RF) | | ||
| 575 | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | | ||
| 576 | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | | ||
| 577 | SSC_BF(RCMR_CKS, SSC_CKS_DIV)); | ||
| 578 | |||
| 579 | rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
| 580 | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | | ||
| 581 | SSC_BF(RFMR_DATNB, channels - 1) | | ||
| 582 | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); | ||
| 583 | |||
| 584 | tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | | ||
| 585 | SSC_BF(TCMR_STTDLY, 1) | | ||
| 586 | SSC_BF(TCMR_START, SSC_START_RISING_RF) | | ||
| 587 | SSC_BF(TCMR_CKI, SSC_CKI_RISING) | | ||
| 588 | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | | ||
| 589 | SSC_BF(TCMR_CKS, SSC_CKS_DIV)); | ||
| 590 | |||
| 591 | tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
| 592 | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | | ||
| 593 | SSC_BF(TFMR_DATNB, channels - 1) | | ||
| 594 | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); | ||
| 595 | break; | ||
| 596 | |||
| 597 | |||
| 598 | case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: | ||
| 599 | default: | ||
| 600 | pr_warning("at32-ssc: unsupported DAI format 0x%x\n", | ||
| 601 | ssc_p->daifmt); | ||
| 602 | return -EINVAL; | ||
| 603 | break; | ||
| 604 | } | ||
| 605 | pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", | ||
| 606 | rcmr, rfmr, tcmr, tfmr); | ||
| 607 | |||
| 608 | |||
| 609 | if (!ssc_p->initialized) { | ||
| 610 | /* enable peripheral clock */ | ||
| 611 | pr_debug("at32-ssc: Starting clock\n"); | ||
| 612 | clk_enable(ssc_p->ssc->clk); | ||
| 613 | |||
| 614 | /* Reset the SSC and its PDC registers */ | ||
| 615 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); | ||
| 616 | |||
| 617 | ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); | ||
| 618 | ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); | ||
| 619 | ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); | ||
| 620 | ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); | ||
| 621 | |||
| 622 | ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); | ||
| 623 | ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); | ||
| 624 | ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); | ||
| 625 | ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); | ||
| 626 | |||
| 627 | ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, | ||
| 628 | ssc_p->name, ssc_p); | ||
| 629 | if (ret < 0) { | ||
| 630 | pr_warning("at32-ssc: request irq failed (%d)\n", ret); | ||
| 631 | pr_debug("at32-ssc: Stopping clock\n"); | ||
| 632 | clk_disable(ssc_p->ssc->clk); | ||
| 633 | return ret; | ||
| 634 | } | ||
| 635 | |||
| 636 | ssc_p->initialized = 1; | ||
| 637 | } | ||
| 638 | |||
| 639 | /* Set SSC clock mode register */ | ||
| 640 | ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); | ||
| 641 | |||
| 642 | /* set receive clock mode and format */ | ||
| 643 | ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); | ||
| 644 | ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); | ||
| 645 | |||
| 646 | /* set transmit clock mode and format */ | ||
| 647 | ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); | ||
| 648 | ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); | ||
| 649 | |||
| 650 | pr_debug("at32-ssc: SSC initialized\n"); | ||
| 651 | return 0; | ||
| 652 | } | ||
| 653 | |||
| 654 | |||
| 655 | |||
| 656 | static int at32_ssc_prepare(struct snd_pcm_substream *substream) | ||
| 657 | { | ||
| 658 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 659 | struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
| 660 | struct at32_pcm_dma_params *dma_params; | ||
| 661 | |||
| 662 | dma_params = ssc_p->dma_params[substream->stream]; | ||
| 663 | |||
| 664 | ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable); | ||
| 665 | |||
| 666 | return 0; | ||
| 667 | } | ||
| 668 | |||
| 669 | |||
| 670 | |||
| 671 | #ifdef CONFIG_PM | ||
| 672 | static int at32_ssc_suspend(struct platform_device *pdev, | ||
| 673 | struct snd_soc_dai *cpu_dai) | ||
| 674 | { | ||
| 675 | struct at32_ssc_info *ssc_p; | ||
| 676 | |||
| 677 | if (!cpu_dai->active) | ||
| 678 | return 0; | ||
| 679 | |||
| 680 | ssc_p = &ssc_info[cpu_dai->id]; | ||
| 681 | |||
| 682 | /* Save the status register before disabling transmit and receive */ | ||
| 683 | ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); | ||
| 684 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); | ||
| 685 | |||
| 686 | /* Save the current interrupt mask, then disable unmasked interrupts */ | ||
| 687 | ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); | ||
| 688 | ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); | ||
| 689 | |||
| 690 | ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); | ||
| 691 | ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); | ||
| 692 | ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); | ||
| 693 | ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); | ||
| 694 | ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); | ||
| 695 | |||
| 696 | return 0; | ||
| 697 | } | ||
| 698 | |||
| 699 | |||
| 700 | |||
| 701 | static int at32_ssc_resume(struct platform_device *pdev, | ||
| 702 | struct snd_soc_dai *cpu_dai) | ||
| 703 | { | ||
| 704 | struct at32_ssc_info *ssc_p; | ||
| 705 | u32 cr; | ||
| 706 | |||
| 707 | if (!cpu_dai->active) | ||
| 708 | return 0; | ||
| 709 | |||
| 710 | ssc_p = &ssc_info[cpu_dai->id]; | ||
| 711 | |||
| 712 | /* restore SSC register settings */ | ||
| 713 | ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); | ||
| 714 | ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); | ||
| 715 | ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); | ||
| 716 | ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); | ||
| 717 | ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); | ||
| 718 | |||
| 719 | /* re-enable interrupts */ | ||
| 720 | ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); | ||
| 721 | |||
| 722 | /* Re-enable recieve and transmit as appropriate */ | ||
| 723 | cr = 0; | ||
| 724 | cr |= | ||
| 725 | (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; | ||
| 726 | cr |= | ||
| 727 | (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; | ||
| 728 | ssc_writel(ssc_p->ssc->regs, CR, cr); | ||
| 729 | |||
| 730 | return 0; | ||
| 731 | } | ||
| 732 | #else /* CONFIG_PM */ | ||
| 733 | # define at32_ssc_suspend NULL | ||
| 734 | # define at32_ssc_resume NULL | ||
| 735 | #endif /* CONFIG_PM */ | ||
| 736 | |||
| 737 | |||
| 738 | #define AT32_SSC_RATES \ | ||
| 739 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | ||
| 740 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
| 741 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
| 742 | |||
| 743 | |||
| 744 | #define AT32_SSC_FORMATS \ | ||
| 745 | (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16 | \ | ||
| 746 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32) | ||
| 747 | |||
| 748 | |||
| 749 | struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = { | ||
| 750 | { | ||
| 751 | .name = "at32-ssc0", | ||
| 752 | .id = 0, | ||
| 753 | .type = SND_SOC_DAI_PCM, | ||
| 754 | .suspend = at32_ssc_suspend, | ||
| 755 | .resume = at32_ssc_resume, | ||
| 756 | .playback = { | ||
| 757 | .channels_min = 1, | ||
| 758 | .channels_max = 2, | ||
| 759 | .rates = AT32_SSC_RATES, | ||
| 760 | .formats = AT32_SSC_FORMATS, | ||
| 761 | }, | ||
| 762 | .capture = { | ||
| 763 | .channels_min = 1, | ||
| 764 | .channels_max = 2, | ||
| 765 | .rates = AT32_SSC_RATES, | ||
| 766 | .formats = AT32_SSC_FORMATS, | ||
| 767 | }, | ||
| 768 | .ops = { | ||
| 769 | .startup = at32_ssc_startup, | ||
| 770 | .shutdown = at32_ssc_shutdown, | ||
| 771 | .prepare = at32_ssc_prepare, | ||
| 772 | .hw_params = at32_ssc_hw_params, | ||
| 773 | }, | ||
| 774 | .dai_ops = { | ||
| 775 | .set_sysclk = at32_ssc_set_dai_sysclk, | ||
| 776 | .set_fmt = at32_ssc_set_dai_fmt, | ||
| 777 | .set_clkdiv = at32_ssc_set_dai_clkdiv, | ||
| 778 | }, | ||
| 779 | .private_data = &ssc_info[0], | ||
| 780 | }, | ||
| 781 | { | ||
| 782 | .name = "at32-ssc1", | ||
| 783 | .id = 1, | ||
| 784 | .type = SND_SOC_DAI_PCM, | ||
| 785 | .suspend = at32_ssc_suspend, | ||
| 786 | .resume = at32_ssc_resume, | ||
| 787 | .playback = { | ||
| 788 | .channels_min = 1, | ||
| 789 | .channels_max = 2, | ||
| 790 | .rates = AT32_SSC_RATES, | ||
| 791 | .formats = AT32_SSC_FORMATS, | ||
| 792 | }, | ||
| 793 | .capture = { | ||
| 794 | .channels_min = 1, | ||
| 795 | .channels_max = 2, | ||
| 796 | .rates = AT32_SSC_RATES, | ||
| 797 | .formats = AT32_SSC_FORMATS, | ||
| 798 | }, | ||
| 799 | .ops = { | ||
| 800 | .startup = at32_ssc_startup, | ||
| 801 | .shutdown = at32_ssc_shutdown, | ||
| 802 | .prepare = at32_ssc_prepare, | ||
| 803 | .hw_params = at32_ssc_hw_params, | ||
| 804 | }, | ||
| 805 | .dai_ops = { | ||
| 806 | .set_sysclk = at32_ssc_set_dai_sysclk, | ||
| 807 | .set_fmt = at32_ssc_set_dai_fmt, | ||
| 808 | .set_clkdiv = at32_ssc_set_dai_clkdiv, | ||
| 809 | }, | ||
| 810 | .private_data = &ssc_info[1], | ||
| 811 | }, | ||
| 812 | { | ||
| 813 | .name = "at32-ssc2", | ||
| 814 | .id = 2, | ||
| 815 | .type = SND_SOC_DAI_PCM, | ||
| 816 | .suspend = at32_ssc_suspend, | ||
| 817 | .resume = at32_ssc_resume, | ||
| 818 | .playback = { | ||
| 819 | .channels_min = 1, | ||
| 820 | .channels_max = 2, | ||
| 821 | .rates = AT32_SSC_RATES, | ||
| 822 | .formats = AT32_SSC_FORMATS, | ||
| 823 | }, | ||
| 824 | .capture = { | ||
| 825 | .channels_min = 1, | ||
| 826 | .channels_max = 2, | ||
| 827 | .rates = AT32_SSC_RATES, | ||
| 828 | .formats = AT32_SSC_FORMATS, | ||
| 829 | }, | ||
| 830 | .ops = { | ||
| 831 | .startup = at32_ssc_startup, | ||
| 832 | .shutdown = at32_ssc_shutdown, | ||
| 833 | .prepare = at32_ssc_prepare, | ||
| 834 | .hw_params = at32_ssc_hw_params, | ||
| 835 | }, | ||
| 836 | .dai_ops = { | ||
| 837 | .set_sysclk = at32_ssc_set_dai_sysclk, | ||
| 838 | .set_fmt = at32_ssc_set_dai_fmt, | ||
| 839 | .set_clkdiv = at32_ssc_set_dai_clkdiv, | ||
| 840 | }, | ||
| 841 | .private_data = &ssc_info[2], | ||
| 842 | }, | ||
| 843 | }; | ||
| 844 | EXPORT_SYMBOL_GPL(at32_ssc_dai); | ||
| 845 | |||
| 846 | |||
| 847 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | ||
| 848 | MODULE_DESCRIPTION("AT32 SSC ASoC Interface"); | ||
| 849 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h new file mode 100644 index 000000000000..3c052dbbe460 --- /dev/null +++ b/sound/soc/at32/at32-ssc.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* sound/soc/at32/at32-ssc.h | ||
| 2 | * ASoC SSC interface for Atmel AT32 SoC | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Long Range Systems | ||
| 5 | * Geoffrey Wossum <gwossum@acm.org> | ||
| 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 __SOUND_SOC_AT32_AT32_SSC_H | ||
| 13 | #define __SOUND_SOC_AT32_AT32_SSC_H __FILE__ | ||
| 14 | |||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/atmel-ssc.h> | ||
| 17 | |||
| 18 | #include "at32-pcm.h" | ||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | struct at32_ssc_state { | ||
| 23 | u32 ssc_cmr; | ||
| 24 | u32 ssc_rcmr; | ||
| 25 | u32 ssc_rfmr; | ||
| 26 | u32 ssc_tcmr; | ||
| 27 | u32 ssc_tfmr; | ||
| 28 | u32 ssc_sr; | ||
| 29 | u32 ssc_imr; | ||
| 30 | }; | ||
| 31 | |||
| 32 | |||
| 33 | |||
| 34 | struct at32_ssc_info { | ||
| 35 | char *name; | ||
| 36 | struct ssc_device *ssc; | ||
| 37 | spinlock_t lock; /* lock for dir_mask */ | ||
| 38 | unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ | ||
| 39 | unsigned short initialized; /* true if SSC has been initialized */ | ||
| 40 | unsigned short daifmt; | ||
| 41 | unsigned short cmr_div; | ||
| 42 | unsigned short tcmr_period; | ||
| 43 | unsigned short rcmr_period; | ||
| 44 | struct at32_pcm_dma_params *dma_params[2]; | ||
| 45 | struct at32_ssc_state ssc_state; | ||
| 46 | }; | ||
| 47 | |||
| 48 | |||
| 49 | /* SSC divider ids */ | ||
| 50 | #define AT32_SSC_CMR_DIV 0 /* MCK divider for BCLK */ | ||
| 51 | #define AT32_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ | ||
| 52 | #define AT32_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ | ||
| 53 | |||
| 54 | |||
| 55 | extern struct snd_soc_dai at32_ssc_dai[]; | ||
| 56 | |||
| 57 | |||
| 58 | |||
| 59 | #endif /* __SOUND_SOC_AT32_AT32_SSC_H */ | ||
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c new file mode 100644 index 000000000000..fee5f8e58957 --- /dev/null +++ b/sound/soc/at32/playpaq_wm8510.c | |||
| @@ -0,0 +1,522 @@ | |||
| 1 | /* sound/soc/at32/playpaq_wm8510.c | ||
| 2 | * ASoC machine driver for PlayPaq using WM8510 codec | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Long Range Systems | ||
| 5 | * Geoffrey Wossum <gwossum@acm.org> | ||
| 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 | * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c | ||
| 12 | * | ||
| 13 | * NOTE: If you don't have the AT32 enhanced portmux configured (which | ||
| 14 | * isn't currently in the mainline or Atmel patched kernel), you will | ||
| 15 | * need to set the MCLK pin (PA30) to peripheral A in your board initialization | ||
| 16 | * code. Something like: | ||
| 17 | * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* #define DEBUG */ | ||
| 22 | |||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/moduleparam.h> | ||
| 25 | #include <linux/version.h> | ||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/errno.h> | ||
| 28 | #include <linux/clk.h> | ||
| 29 | #include <linux/timer.h> | ||
| 30 | #include <linux/interrupt.h> | ||
| 31 | #include <linux/platform_device.h> | ||
| 32 | |||
| 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> | ||
| 38 | |||
| 39 | #include <asm/arch/at32ap700x.h> | ||
| 40 | #include <asm/arch/portmux.h> | ||
| 41 | |||
| 42 | #include "../codecs/wm8510.h" | ||
| 43 | #include "at32-pcm.h" | ||
| 44 | #include "at32-ssc.h" | ||
| 45 | |||
| 46 | |||
| 47 | /*-------------------------------------------------------------------------*\ | ||
| 48 | * constants | ||
| 49 | \*-------------------------------------------------------------------------*/ | ||
| 50 | #define MCLK_PIN GPIO_PIN_PA(30) | ||
| 51 | #define MCLK_PERIPH GPIO_PERIPH_A | ||
| 52 | |||
| 53 | |||
| 54 | /*-------------------------------------------------------------------------*\ | ||
| 55 | * data types | ||
| 56 | \*-------------------------------------------------------------------------*/ | ||
| 57 | /* SSC clocking data */ | ||
| 58 | struct ssc_clock_data { | ||
| 59 | /* CMR div */ | ||
| 60 | unsigned int cmr_div; | ||
| 61 | |||
| 62 | /* Frame period (as needed by xCMR.PERIOD) */ | ||
| 63 | unsigned int period; | ||
| 64 | |||
| 65 | /* The SSC clock rate these settings where calculated for */ | ||
| 66 | unsigned long ssc_rate; | ||
| 67 | }; | ||
| 68 | |||
| 69 | |||
| 70 | /*-------------------------------------------------------------------------*\ | ||
| 71 | * module data | ||
| 72 | \*-------------------------------------------------------------------------*/ | ||
| 73 | static struct clk *_gclk0; | ||
| 74 | static struct clk *_pll0; | ||
| 75 | |||
| 76 | #define CODEC_CLK (_gclk0) | ||
| 77 | |||
| 78 | |||
| 79 | /*-------------------------------------------------------------------------*\ | ||
| 80 | * Sound SOC operations | ||
| 81 | \*-------------------------------------------------------------------------*/ | ||
| 82 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
| 83 | static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( | ||
| 84 | struct snd_pcm_hw_params *params, | ||
| 85 | struct snd_soc_dai *cpu_dai) | ||
| 86 | { | ||
| 87 | struct at32_ssc_info *ssc_p = cpu_dai->private_data; | ||
| 88 | struct ssc_device *ssc = ssc_p->ssc; | ||
| 89 | struct ssc_clock_data cd; | ||
| 90 | unsigned int rate, width_bits, channels; | ||
| 91 | unsigned int bitrate, ssc_div; | ||
| 92 | unsigned actual_rate; | ||
| 93 | |||
| 94 | |||
| 95 | /* | ||
| 96 | * Figure out required bitrate | ||
| 97 | */ | ||
| 98 | rate = params_rate(params); | ||
| 99 | channels = params_channels(params); | ||
| 100 | width_bits = snd_pcm_format_physical_width(params_format(params)); | ||
| 101 | bitrate = rate * width_bits * channels; | ||
| 102 | |||
| 103 | |||
| 104 | /* | ||
| 105 | * Figure out required SSC divider and period for required bitrate | ||
| 106 | */ | ||
| 107 | cd.ssc_rate = clk_get_rate(ssc->clk); | ||
| 108 | ssc_div = cd.ssc_rate / bitrate; | ||
| 109 | cd.cmr_div = ssc_div / 2; | ||
| 110 | if (ssc_div & 1) { | ||
| 111 | /* round cmr_div up */ | ||
| 112 | cd.cmr_div++; | ||
| 113 | } | ||
| 114 | cd.period = width_bits - 1; | ||
| 115 | |||
| 116 | |||
| 117 | /* | ||
| 118 | * Find actual rate, compare to requested rate | ||
| 119 | */ | ||
| 120 | actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); | ||
| 121 | pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", | ||
| 122 | rate, actual_rate); | ||
| 123 | |||
| 124 | |||
| 125 | return cd; | ||
| 126 | } | ||
| 127 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
| 128 | |||
| 129 | |||
| 130 | |||
| 131 | static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, | ||
| 132 | struct snd_pcm_hw_params *params) | ||
| 133 | { | ||
| 134 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 135 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
| 136 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
| 137 | struct at32_ssc_info *ssc_p = cpu_dai->private_data; | ||
| 138 | struct ssc_device *ssc = ssc_p->ssc; | ||
| 139 | unsigned int pll_out = 0, bclk = 0, mclk_div = 0; | ||
| 140 | int ret; | ||
| 141 | |||
| 142 | |||
| 143 | /* Due to difficulties with getting the correct clocks from the AT32's | ||
| 144 | * PLL0, we're going to let the CODEC be in charge of all the clocks | ||
| 145 | */ | ||
| 146 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
| 147 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | ||
| 148 | SND_SOC_DAIFMT_NB_NF | | ||
| 149 | SND_SOC_DAIFMT_CBM_CFM); | ||
| 150 | #else | ||
| 151 | struct ssc_clock_data cd; | ||
| 152 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | ||
| 153 | SND_SOC_DAIFMT_NB_NF | | ||
| 154 | SND_SOC_DAIFMT_CBS_CFS); | ||
| 155 | #endif | ||
| 156 | |||
| 157 | if (ssc == NULL) { | ||
| 158 | pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); | ||
| 159 | return -EINVAL; | ||
| 160 | } | ||
| 161 | |||
| 162 | |||
| 163 | /* | ||
| 164 | * Figure out PLL and BCLK dividers for WM8510 | ||
| 165 | */ | ||
| 166 | switch (params_rate(params)) { | ||
| 167 | case 48000: | ||
| 168 | pll_out = 12288000; | ||
| 169 | mclk_div = WM8510_MCLKDIV_1; | ||
| 170 | bclk = WM8510_BCLKDIV_8; | ||
| 171 | break; | ||
| 172 | |||
| 173 | case 44100: | ||
| 174 | pll_out = 11289600; | ||
| 175 | mclk_div = WM8510_MCLKDIV_1; | ||
| 176 | bclk = WM8510_BCLKDIV_8; | ||
| 177 | break; | ||
| 178 | |||
| 179 | case 22050: | ||
| 180 | pll_out = 11289600; | ||
| 181 | mclk_div = WM8510_MCLKDIV_2; | ||
| 182 | bclk = WM8510_BCLKDIV_8; | ||
| 183 | break; | ||
| 184 | |||
| 185 | case 16000: | ||
| 186 | pll_out = 12288000; | ||
| 187 | mclk_div = WM8510_MCLKDIV_3; | ||
| 188 | bclk = WM8510_BCLKDIV_8; | ||
| 189 | break; | ||
| 190 | |||
| 191 | case 11025: | ||
| 192 | pll_out = 11289600; | ||
| 193 | mclk_div = WM8510_MCLKDIV_4; | ||
| 194 | bclk = WM8510_BCLKDIV_8; | ||
| 195 | break; | ||
| 196 | |||
| 197 | case 8000: | ||
| 198 | pll_out = 12288000; | ||
| 199 | mclk_div = WM8510_MCLKDIV_6; | ||
| 200 | bclk = WM8510_BCLKDIV_8; | ||
| 201 | break; | ||
| 202 | |||
| 203 | default: | ||
| 204 | pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", | ||
| 205 | params_rate(params)); | ||
| 206 | return -EINVAL; | ||
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | /* | ||
| 211 | * set CPU and CODEC DAI configuration | ||
| 212 | */ | ||
| 213 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); | ||
| 214 | if (ret < 0) { | ||
| 215 | pr_warning("playpaq_wm8510: " | ||
| 216 | "Failed to set CODEC DAI format (%d)\n", | ||
| 217 | ret); | ||
| 218 | return ret; | ||
| 219 | } | ||
| 220 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); | ||
| 221 | if (ret < 0) { | ||
| 222 | pr_warning("playpaq_wm8510: " | ||
| 223 | "Failed to set CPU DAI format (%d)\n", | ||
| 224 | ret); | ||
| 225 | return ret; | ||
| 226 | } | ||
| 227 | |||
| 228 | |||
| 229 | /* | ||
| 230 | * Set CPU clock configuration | ||
| 231 | */ | ||
| 232 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
| 233 | cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); | ||
| 234 | pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", | ||
| 235 | cd.cmr_div, cd.period); | ||
| 236 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); | ||
| 237 | if (ret < 0) { | ||
| 238 | pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", | ||
| 239 | ret); | ||
| 240 | return ret; | ||
| 241 | } | ||
| 242 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, | ||
| 243 | cd.period); | ||
| 244 | if (ret < 0) { | ||
| 245 | pr_warning("playpaq_wm8510: " | ||
| 246 | "Failed to set CPU transmit period (%d)\n", | ||
| 247 | ret); | ||
| 248 | return ret; | ||
| 249 | } | ||
| 250 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
| 251 | |||
| 252 | |||
| 253 | /* | ||
| 254 | * Set CODEC clock configuration | ||
| 255 | */ | ||
| 256 | pr_debug("playpaq_wm8510: " | ||
| 257 | "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", | ||
| 258 | clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); | ||
| 259 | |||
| 260 | |||
| 261 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
| 262 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); | ||
| 263 | if (ret < 0) { | ||
| 264 | pr_warning | ||
| 265 | ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", | ||
| 266 | ret); | ||
| 267 | return ret; | ||
| 268 | } | ||
| 269 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
| 270 | |||
| 271 | |||
| 272 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
| 273 | clk_get_rate(CODEC_CLK), pll_out); | ||
| 274 | if (ret < 0) { | ||
| 275 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", | ||
| 276 | ret); | ||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | |||
| 281 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); | ||
| 282 | if (ret < 0) { | ||
| 283 | pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", | ||
| 284 | ret); | ||
| 285 | return ret; | ||
| 286 | } | ||
| 287 | |||
| 288 | |||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | |||
| 292 | |||
| 293 | |||
| 294 | static struct snd_soc_ops playpaq_wm8510_ops = { | ||
| 295 | .hw_params = playpaq_wm8510_hw_params, | ||
| 296 | }; | ||
| 297 | |||
| 298 | |||
| 299 | |||
| 300 | static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { | ||
| 301 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
| 302 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
| 303 | }; | ||
| 304 | |||
| 305 | |||
| 306 | |||
| 307 | static const char *intercon[][3] = { | ||
| 308 | /* speaker connected to SPKOUT */ | ||
| 309 | {"Ext Spk", NULL, "SPKOUTP"}, | ||
| 310 | {"Ext Spk", NULL, "SPKOUTN"}, | ||
| 311 | |||
| 312 | {"Mic Bias", NULL, "Int Mic"}, | ||
| 313 | {"MICN", NULL, "Mic Bias"}, | ||
| 314 | {"MICP", NULL, "Mic Bias"}, | ||
| 315 | |||
| 316 | /* Terminator */ | ||
| 317 | {NULL, NULL, NULL}, | ||
| 318 | }; | ||
| 319 | |||
| 320 | |||
| 321 | |||
| 322 | static int playpaq_wm8510_init(struct snd_soc_codec *codec) | ||
| 323 | { | ||
| 324 | int i; | ||
| 325 | |||
| 326 | /* | ||
| 327 | * Add DAPM widgets | ||
| 328 | */ | ||
| 329 | for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) | ||
| 330 | snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]); | ||
| 331 | |||
| 332 | |||
| 333 | |||
| 334 | /* | ||
| 335 | * Setup audio path interconnects | ||
| 336 | */ | ||
| 337 | for (i = 0; intercon[i][0] != NULL; i++) { | ||
| 338 | snd_soc_dapm_connect_input(codec, | ||
| 339 | intercon[i][0], | ||
| 340 | intercon[i][1], intercon[i][2]); | ||
| 341 | } | ||
| 342 | |||
| 343 | |||
| 344 | /* always connected pins */ | ||
| 345 | snd_soc_dapm_enable_pin(codec, "Int Mic"); | ||
| 346 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
| 347 | snd_soc_dapm_sync(codec); | ||
| 348 | |||
| 349 | |||
| 350 | |||
| 351 | /* Make CSB show PLL rate */ | ||
| 352 | snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV, | ||
| 353 | WM8510_OPCLKDIV_1 | 4); | ||
| 354 | |||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | |||
| 358 | |||
| 359 | |||
| 360 | static struct snd_soc_dai_link playpaq_wm8510_dai = { | ||
| 361 | .name = "WM8510", | ||
| 362 | .stream_name = "WM8510 PCM", | ||
| 363 | .cpu_dai = &at32_ssc_dai[0], | ||
| 364 | .codec_dai = &wm8510_dai, | ||
| 365 | .init = playpaq_wm8510_init, | ||
| 366 | .ops = &playpaq_wm8510_ops, | ||
| 367 | }; | ||
| 368 | |||
| 369 | |||
| 370 | |||
| 371 | static struct snd_soc_machine snd_soc_machine_playpaq = { | ||
| 372 | .name = "LRS_PlayPaq_WM8510", | ||
| 373 | .dai_link = &playpaq_wm8510_dai, | ||
| 374 | .num_links = 1, | ||
| 375 | }; | ||
| 376 | |||
| 377 | |||
| 378 | |||
| 379 | static struct wm8510_setup_data playpaq_wm8510_setup = { | ||
| 380 | .i2c_address = 0x1a, | ||
| 381 | }; | ||
| 382 | |||
| 383 | |||
| 384 | |||
| 385 | static struct snd_soc_device playpaq_wm8510_snd_devdata = { | ||
| 386 | .machine = &snd_soc_machine_playpaq, | ||
| 387 | .platform = &at32_soc_platform, | ||
| 388 | .codec_dev = &soc_codec_dev_wm8510, | ||
| 389 | .codec_data = &playpaq_wm8510_setup, | ||
| 390 | }; | ||
| 391 | |||
| 392 | static struct platform_device *playpaq_snd_device; | ||
| 393 | |||
| 394 | |||
| 395 | static int __init playpaq_asoc_init(void) | ||
| 396 | { | ||
| 397 | int ret = 0; | ||
| 398 | struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; | ||
| 399 | struct ssc_device *ssc = NULL; | ||
| 400 | |||
| 401 | |||
| 402 | /* | ||
| 403 | * Request SSC device | ||
| 404 | */ | ||
| 405 | ssc = ssc_request(0); | ||
| 406 | if (IS_ERR(ssc)) { | ||
| 407 | ret = PTR_ERR(ssc); | ||
| 408 | ssc = NULL; | ||
| 409 | goto err_ssc; | ||
| 410 | } | ||
| 411 | ssc_p->ssc = ssc; | ||
| 412 | |||
| 413 | |||
| 414 | /* | ||
| 415 | * Configure MCLK for WM8510 | ||
| 416 | */ | ||
| 417 | _gclk0 = clk_get(NULL, "gclk0"); | ||
| 418 | if (IS_ERR(_gclk0)) { | ||
| 419 | _gclk0 = NULL; | ||
| 420 | goto err_gclk0; | ||
| 421 | } | ||
| 422 | _pll0 = clk_get(NULL, "pll0"); | ||
| 423 | if (IS_ERR(_pll0)) { | ||
| 424 | _pll0 = NULL; | ||
| 425 | goto err_pll0; | ||
| 426 | } | ||
| 427 | if (clk_set_parent(_gclk0, _pll0)) { | ||
| 428 | pr_warning("snd-soc-playpaq: " | ||
| 429 | "Failed to set PLL0 as parent for DAC clock\n"); | ||
| 430 | goto err_set_clk; | ||
| 431 | } | ||
| 432 | clk_set_rate(CODEC_CLK, 12000000); | ||
| 433 | clk_enable(CODEC_CLK); | ||
| 434 | |||
| 435 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | ||
| 436 | at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); | ||
| 437 | #endif | ||
| 438 | |||
| 439 | |||
| 440 | /* | ||
| 441 | * Create and register platform device | ||
| 442 | */ | ||
| 443 | playpaq_snd_device = platform_device_alloc("soc-audio", 0); | ||
| 444 | if (playpaq_snd_device == NULL) { | ||
| 445 | ret = -ENOMEM; | ||
| 446 | goto err_device_alloc; | ||
| 447 | } | ||
| 448 | |||
| 449 | platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata); | ||
| 450 | playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev; | ||
| 451 | |||
| 452 | ret = platform_device_add(playpaq_snd_device); | ||
| 453 | if (ret) { | ||
| 454 | pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", | ||
| 455 | ret); | ||
| 456 | goto err_device_add; | ||
| 457 | } | ||
| 458 | |||
| 459 | return 0; | ||
| 460 | |||
| 461 | |||
| 462 | err_device_add: | ||
| 463 | if (playpaq_snd_device != NULL) { | ||
| 464 | platform_device_put(playpaq_snd_device); | ||
| 465 | playpaq_snd_device = NULL; | ||
| 466 | } | ||
| 467 | err_device_alloc: | ||
| 468 | err_set_clk: | ||
| 469 | if (_pll0 != NULL) { | ||
| 470 | clk_put(_pll0); | ||
| 471 | _pll0 = NULL; | ||
| 472 | } | ||
| 473 | err_pll0: | ||
| 474 | if (_gclk0 != NULL) { | ||
| 475 | clk_put(_gclk0); | ||
| 476 | _gclk0 = NULL; | ||
| 477 | } | ||
| 478 | err_gclk0: | ||
| 479 | if (ssc != NULL) { | ||
| 480 | ssc_free(ssc); | ||
| 481 | ssc = NULL; | ||
| 482 | } | ||
| 483 | err_ssc: | ||
| 484 | return ret; | ||
| 485 | } | ||
| 486 | |||
| 487 | |||
| 488 | static void __exit playpaq_asoc_exit(void) | ||
| 489 | { | ||
| 490 | struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; | ||
| 491 | struct ssc_device *ssc; | ||
| 492 | |||
| 493 | if (ssc_p != NULL) { | ||
| 494 | ssc = ssc_p->ssc; | ||
| 495 | if (ssc != NULL) | ||
| 496 | ssc_free(ssc); | ||
| 497 | ssc_p->ssc = NULL; | ||
| 498 | } | ||
| 499 | |||
| 500 | if (_gclk0 != NULL) { | ||
| 501 | clk_put(_gclk0); | ||
| 502 | _gclk0 = NULL; | ||
| 503 | } | ||
| 504 | if (_pll0 != NULL) { | ||
| 505 | clk_put(_pll0); | ||
| 506 | _pll0 = NULL; | ||
| 507 | } | ||
| 508 | |||
| 509 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | ||
| 510 | at32_free_pin(MCLK_PIN); | ||
| 511 | #endif | ||
| 512 | |||
| 513 | platform_device_unregister(playpaq_snd_device); | ||
| 514 | playpaq_snd_device = NULL; | ||
| 515 | } | ||
| 516 | |||
| 517 | module_init(playpaq_asoc_init); | ||
| 518 | module_exit(playpaq_asoc_exit); | ||
| 519 | |||
| 520 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | ||
| 521 | MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); | ||
| 522 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig index 5cb93fd3a407..905186502e00 100644 --- a/sound/soc/at91/Kconfig +++ b/sound/soc/at91/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config SND_AT91_SOC | 1 | config SND_AT91_SOC |
| 2 | tristate "SoC Audio for the Atmel AT91 System-on-Chip" | 2 | tristate "SoC Audio for the Atmel AT91 System-on-Chip" |
| 3 | depends on ARCH_AT91 && SND_SOC | 3 | depends on ARCH_AT91 |
| 4 | help | 4 | help |
| 5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
| 6 | the AT91 SSC interface. You will also need | 6 | the AT91 SSC interface. You will also need |
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c index ccac6bd2889c..d47492b2b6e5 100644 --- a/sound/soc/at91/at91-pcm.c +++ b/sound/soc/at91/at91-pcm.c | |||
| @@ -318,7 +318,7 @@ static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, | |||
| 318 | static u64 at91_pcm_dmamask = 0xffffffff; | 318 | static u64 at91_pcm_dmamask = 0xffffffff; |
| 319 | 319 | ||
| 320 | static int at91_pcm_new(struct snd_card *card, | 320 | static int at91_pcm_new(struct snd_card *card, |
| 321 | struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) | 321 | struct snd_soc_dai *dai, struct snd_pcm *pcm) |
| 322 | { | 322 | { |
| 323 | int ret = 0; | 323 | int ret = 0; |
| 324 | 324 | ||
| @@ -367,7 +367,7 @@ static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
| 367 | 367 | ||
| 368 | #ifdef CONFIG_PM | 368 | #ifdef CONFIG_PM |
| 369 | static int at91_pcm_suspend(struct platform_device *pdev, | 369 | static int at91_pcm_suspend(struct platform_device *pdev, |
| 370 | struct snd_soc_cpu_dai *dai) | 370 | struct snd_soc_dai *dai) |
| 371 | { | 371 | { |
| 372 | struct snd_pcm_runtime *runtime = dai->runtime; | 372 | struct snd_pcm_runtime *runtime = dai->runtime; |
| 373 | struct at91_runtime_data *prtd; | 373 | struct at91_runtime_data *prtd; |
| @@ -392,7 +392,7 @@ static int at91_pcm_suspend(struct platform_device *pdev, | |||
| 392 | } | 392 | } |
| 393 | 393 | ||
| 394 | static int at91_pcm_resume(struct platform_device *pdev, | 394 | static int at91_pcm_resume(struct platform_device *pdev, |
| 395 | struct snd_soc_cpu_dai *dai) | 395 | struct snd_soc_dai *dai) |
| 396 | { | 396 | { |
| 397 | struct snd_pcm_runtime *runtime = dai->runtime; | 397 | struct snd_pcm_runtime *runtime = dai->runtime; |
| 398 | struct at91_runtime_data *prtd; | 398 | struct at91_runtime_data *prtd; |
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c index bc35d00a38f8..c3625b665c5a 100644 --- a/sound/soc/at91/at91-ssc.c +++ b/sound/soc/at91/at91-ssc.c | |||
| @@ -281,7 +281,7 @@ static void at91_ssc_shutdown(struct snd_pcm_substream *substream) | |||
| 281 | /* | 281 | /* |
| 282 | * Record the SSC system clock rate. | 282 | * Record the SSC system clock rate. |
| 283 | */ | 283 | */ |
| 284 | static int at91_ssc_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 284 | static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
| 285 | int clk_id, unsigned int freq, int dir) | 285 | int clk_id, unsigned int freq, int dir) |
| 286 | { | 286 | { |
| 287 | /* | 287 | /* |
| @@ -303,7 +303,7 @@ static int at91_ssc_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
| 303 | /* | 303 | /* |
| 304 | * Record the DAI format for use in hw_params(). | 304 | * Record the DAI format for use in hw_params(). |
| 305 | */ | 305 | */ |
| 306 | static int at91_ssc_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 306 | static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
| 307 | unsigned int fmt) | 307 | unsigned int fmt) |
| 308 | { | 308 | { |
| 309 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | 309 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; |
| @@ -315,7 +315,7 @@ static int at91_ssc_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | |||
| 315 | /* | 315 | /* |
| 316 | * Record SSC clock dividers for use in hw_params(). | 316 | * Record SSC clock dividers for use in hw_params(). |
| 317 | */ | 317 | */ |
| 318 | static int at91_ssc_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 318 | static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, |
| 319 | int div_id, int div) | 319 | int div_id, int div) |
| 320 | { | 320 | { |
| 321 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | 321 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; |
| @@ -634,7 +634,7 @@ static int at91_ssc_prepare(struct snd_pcm_substream *substream) | |||
| 634 | 634 | ||
| 635 | #ifdef CONFIG_PM | 635 | #ifdef CONFIG_PM |
| 636 | static int at91_ssc_suspend(struct platform_device *pdev, | 636 | static int at91_ssc_suspend(struct platform_device *pdev, |
| 637 | struct snd_soc_cpu_dai *cpu_dai) | 637 | struct snd_soc_dai *cpu_dai) |
| 638 | { | 638 | { |
| 639 | struct at91_ssc_info *ssc_p; | 639 | struct at91_ssc_info *ssc_p; |
| 640 | 640 | ||
| @@ -662,7 +662,7 @@ static int at91_ssc_suspend(struct platform_device *pdev, | |||
| 662 | } | 662 | } |
| 663 | 663 | ||
| 664 | static int at91_ssc_resume(struct platform_device *pdev, | 664 | static int at91_ssc_resume(struct platform_device *pdev, |
| 665 | struct snd_soc_cpu_dai *cpu_dai) | 665 | struct snd_soc_dai *cpu_dai) |
| 666 | { | 666 | { |
| 667 | struct at91_ssc_info *ssc_p; | 667 | struct at91_ssc_info *ssc_p; |
| 668 | 668 | ||
| @@ -700,7 +700,7 @@ static int at91_ssc_resume(struct platform_device *pdev, | |||
| 700 | #define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ | 700 | #define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ |
| 701 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 701 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
| 702 | 702 | ||
| 703 | struct snd_soc_cpu_dai at91_ssc_dai[NUM_SSC_DEVICES] = { | 703 | struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = { |
| 704 | { .name = "at91-ssc0", | 704 | { .name = "at91-ssc0", |
| 705 | .id = 0, | 705 | .id = 0, |
| 706 | .type = SND_SOC_DAI_PCM, | 706 | .type = SND_SOC_DAI_PCM, |
diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h index b188f973df9f..6b7bf382d06f 100644 --- a/sound/soc/at91/at91-ssc.h +++ b/sound/soc/at91/at91-ssc.h | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | #define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ | 21 | #define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ |
| 22 | #define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ | 22 | #define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ |
| 23 | 23 | ||
| 24 | extern struct snd_soc_cpu_dai at91_ssc_dai[]; | 24 | extern struct snd_soc_dai at91_ssc_dai[]; |
| 25 | 25 | ||
| 26 | #endif /* _AT91_SSC_H */ | 26 | #endif /* _AT91_SSC_H */ |
| 27 | 27 | ||
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c index 1347dcf3f80b..d532de954241 100644 --- a/sound/soc/at91/eti_b1_wm8731.c +++ b/sound/soc/at91/eti_b1_wm8731.c | |||
| @@ -53,18 +53,18 @@ static struct clk *pllb_clk; | |||
| 53 | static int eti_b1_startup(struct snd_pcm_substream *substream) | 53 | static int eti_b1_startup(struct snd_pcm_substream *substream) |
| 54 | { | 54 | { |
| 55 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 55 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 56 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 56 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 57 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 57 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 58 | int ret; | 58 | int ret; |
| 59 | 59 | ||
| 60 | /* cpu clock is the AT91 master clock sent to the SSC */ | 60 | /* cpu clock is the AT91 master clock sent to the SSC */ |
| 61 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK, | 61 | ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK, |
| 62 | 60000000, SND_SOC_CLOCK_IN); | 62 | 60000000, SND_SOC_CLOCK_IN); |
| 63 | if (ret < 0) | 63 | if (ret < 0) |
| 64 | return ret; | 64 | return ret; |
| 65 | 65 | ||
| 66 | /* codec system clock is supplied by PCK1, set to 12MHz */ | 66 | /* codec system clock is supplied by PCK1, set to 12MHz */ |
| 67 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, | 67 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, |
| 68 | 12000000, SND_SOC_CLOCK_IN); | 68 | 12000000, SND_SOC_CLOCK_IN); |
| 69 | if (ret < 0) | 69 | if (ret < 0) |
| 70 | return ret; | 70 | return ret; |
| @@ -87,8 +87,8 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
| 87 | struct snd_pcm_hw_params *params) | 87 | struct snd_pcm_hw_params *params) |
| 88 | { | 88 | { |
| 89 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 89 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 90 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 90 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 91 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 91 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 92 | int ret; | 92 | int ret; |
| 93 | 93 | ||
| 94 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | 94 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE |
| @@ -96,13 +96,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
| 96 | int cmr_div, period; | 96 | int cmr_div, period; |
| 97 | 97 | ||
| 98 | /* set codec DAI configuration */ | 98 | /* set codec DAI configuration */ |
| 99 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 99 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
| 100 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 100 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 101 | if (ret < 0) | 101 | if (ret < 0) |
| 102 | return ret; | 102 | return ret; |
| 103 | 103 | ||
| 104 | /* set cpu DAI configuration */ | 104 | /* set cpu DAI configuration */ |
| 105 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 105 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
| 106 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 106 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 107 | if (ret < 0) | 107 | if (ret < 0) |
| 108 | return ret; | 108 | return ret; |
| @@ -141,17 +141,17 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | /* set the MCK divider for BCLK */ | 143 | /* set the MCK divider for BCLK */ |
| 144 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); | 144 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); |
| 145 | if (ret < 0) | 145 | if (ret < 0) |
| 146 | return ret; | 146 | return ret; |
| 147 | 147 | ||
| 148 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 148 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 149 | /* set the BCLK divider for DACLRC */ | 149 | /* set the BCLK divider for DACLRC */ |
| 150 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, | 150 | ret = snd_soc_dai_set_clkdiv(cpu_dai, |
| 151 | AT91SSC_TCMR_PERIOD, period); | 151 | AT91SSC_TCMR_PERIOD, period); |
| 152 | } else { | 152 | } else { |
| 153 | /* set the BCLK divider for ADCLRC */ | 153 | /* set the BCLK divider for ADCLRC */ |
| 154 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, | 154 | ret = snd_soc_dai_set_clkdiv(cpu_dai, |
| 155 | AT91SSC_RCMR_PERIOD, period); | 155 | AT91SSC_RCMR_PERIOD, period); |
| 156 | } | 156 | } |
| 157 | if (ret < 0) | 157 | if (ret < 0) |
| @@ -163,13 +163,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
| 163 | */ | 163 | */ |
| 164 | 164 | ||
| 165 | /* set codec DAI configuration */ | 165 | /* set codec DAI configuration */ |
| 166 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 166 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
| 167 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 167 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
| 168 | if (ret < 0) | 168 | if (ret < 0) |
| 169 | return ret; | 169 | return ret; |
| 170 | 170 | ||
| 171 | /* set cpu DAI configuration */ | 171 | /* set cpu DAI configuration */ |
| 172 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 172 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
| 173 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 173 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
| 174 | if (ret < 0) | 174 | if (ret < 0) |
| 175 | return ret; | 175 | return ret; |
| @@ -191,7 +191,7 @@ static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = { | |||
| 191 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | 191 | SND_SOC_DAPM_SPK("Ext Spk", NULL), |
| 192 | }; | 192 | }; |
| 193 | 193 | ||
| 194 | static const char *intercon[][3] = { | 194 | static const struct snd_soc_dapm_route intercon[] = { |
| 195 | 195 | ||
| 196 | /* speaker connected to LHPOUT */ | 196 | /* speaker connected to LHPOUT */ |
| 197 | {"Ext Spk", NULL, "LHPOUT"}, | 197 | {"Ext Spk", NULL, "LHPOUT"}, |
| @@ -199,9 +199,6 @@ static const char *intercon[][3] = { | |||
| 199 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ | 199 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ |
| 200 | {"MICIN", NULL, "Mic Bias"}, | 200 | {"MICIN", NULL, "Mic Bias"}, |
| 201 | {"Mic Bias", NULL, "Int Mic"}, | 201 | {"Mic Bias", NULL, "Int Mic"}, |
| 202 | |||
| 203 | /* terminator */ | ||
| 204 | {NULL, NULL, NULL}, | ||
| 205 | }; | 202 | }; |
| 206 | 203 | ||
| 207 | /* | 204 | /* |
| @@ -209,30 +206,24 @@ static const char *intercon[][3] = { | |||
| 209 | */ | 206 | */ |
| 210 | static int eti_b1_wm8731_init(struct snd_soc_codec *codec) | 207 | static int eti_b1_wm8731_init(struct snd_soc_codec *codec) |
| 211 | { | 208 | { |
| 212 | int i; | ||
| 213 | |||
| 214 | DBG("eti_b1_wm8731_init() called\n"); | 209 | DBG("eti_b1_wm8731_init() called\n"); |
| 215 | 210 | ||
| 216 | /* Add specific widgets */ | 211 | /* Add specific widgets */ |
| 217 | for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) { | 212 | snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets, |
| 218 | snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]); | 213 | ARRAY_SIZE(eti_b1_dapm_widgets)); |
| 219 | } | ||
| 220 | 214 | ||
| 221 | /* Set up specific audio path interconnects */ | 215 | /* Set up specific audio path interconnects */ |
| 222 | for(i = 0; intercon[i][0] != NULL; i++) { | 216 | snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon)); |
| 223 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
| 224 | intercon[i][1], intercon[i][2]); | ||
| 225 | } | ||
| 226 | 217 | ||
| 227 | /* not connected */ | 218 | /* not connected */ |
| 228 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | 219 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); |
| 229 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | 220 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); |
| 230 | 221 | ||
| 231 | /* always connected */ | 222 | /* always connected */ |
| 232 | snd_soc_dapm_set_endpoint(codec, "Int Mic", 1); | 223 | snd_soc_dapm_enable_pin(codec, "Int Mic"); |
| 233 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); | 224 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
| 234 | 225 | ||
| 235 | snd_soc_dapm_sync_endpoints(codec); | 226 | snd_soc_dapm_sync(codec); |
| 236 | 227 | ||
| 237 | return 0; | 228 | return 0; |
| 238 | } | 229 | } |
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig new file mode 100644 index 000000000000..410a893aa66b --- /dev/null +++ b/sound/soc/au1x/Kconfig | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | ## | ||
| 2 | ## Au1200/Au1550 PSC + DBDMA | ||
| 3 | ## | ||
| 4 | config SND_SOC_AU1XPSC | ||
| 5 | tristate "SoC Audio for Au1200/Au1250/Au1550" | ||
| 6 | depends on SOC_AU1200 || SOC_AU1550 | ||
| 7 | help | ||
| 8 | This option enables support for the Programmable Serial | ||
| 9 | Controllers in AC97 and I2S mode, and the Descriptor-Based DMA | ||
| 10 | Controller (DBDMA) as found on the Au1200/Au1250/Au1550 SoC. | ||
| 11 | |||
| 12 | config SND_SOC_AU1XPSC_I2S | ||
| 13 | tristate | ||
| 14 | |||
| 15 | config SND_SOC_AU1XPSC_AC97 | ||
| 16 | tristate | ||
| 17 | select AC97_BUS | ||
| 18 | select SND_AC97_CODEC | ||
| 19 | select SND_SOC_AC97_BUS | ||
| 20 | |||
| 21 | |||
| 22 | ## | ||
| 23 | ## Boards | ||
| 24 | ## | ||
| 25 | config SND_SOC_SAMPLE_PSC_AC97 | ||
| 26 | tristate "Sample Au12x0/Au1550 PSC AC97 sound machine" | ||
| 27 | depends on SND_SOC_AU1XPSC | ||
| 28 | select SND_SOC_AU1XPSC_AC97 | ||
| 29 | select SND_SOC_AC97_CODEC | ||
| 30 | help | ||
| 31 | This is a sample AC97 sound machine for use in Au12x0/Au1550 | ||
| 32 | based systems which have audio on PSC1 (e.g. Db1200 demoboard). | ||
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile new file mode 100644 index 000000000000..6c6950b8003a --- /dev/null +++ b/sound/soc/au1x/Makefile | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | # Au1200/Au1550 PSC audio | ||
| 2 | snd-soc-au1xpsc-dbdma-objs := dbdma2.o | ||
| 3 | snd-soc-au1xpsc-i2s-objs := psc-i2s.o | ||
| 4 | snd-soc-au1xpsc-ac97-objs := psc-ac97.o | ||
| 5 | |||
| 6 | obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o | ||
| 7 | obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o | ||
| 8 | obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o | ||
| 9 | |||
| 10 | # Boards | ||
| 11 | snd-soc-sample-ac97-objs := sample-ac97.o | ||
| 12 | |||
| 13 | obj-$(CONFIG_SND_SOC_SAMPLE_PSC_AC97) += snd-soc-sample-ac97.o | ||
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c new file mode 100644 index 000000000000..1466d9328800 --- /dev/null +++ b/sound/soc/au1x/dbdma2.c | |||
| @@ -0,0 +1,421 @@ | |||
| 1 | /* | ||
| 2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
| 3 | * | ||
| 4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
| 5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
| 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 | * DMA glue for Au1x-PSC audio. | ||
| 12 | * | ||
| 13 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
| 14 | * of a PSC. Multiple independent audio devices are impossible | ||
| 15 | * with ASoC v1. | ||
| 16 | */ | ||
| 17 | |||
| 18 | |||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/dma-mapping.h> | ||
| 24 | |||
| 25 | #include <sound/core.h> | ||
| 26 | #include <sound/pcm.h> | ||
| 27 | #include <sound/pcm_params.h> | ||
| 28 | #include <sound/soc.h> | ||
| 29 | |||
| 30 | #include <asm/mach-au1x00/au1000.h> | ||
| 31 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | ||
| 32 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
| 33 | |||
| 34 | #include "psc.h" | ||
| 35 | |||
| 36 | /*#define PCM_DEBUG*/ | ||
| 37 | |||
| 38 | #define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x) | ||
| 39 | #ifdef PCM_DEBUG | ||
| 40 | #define DBG MSG | ||
| 41 | #else | ||
| 42 | #define DBG(x...) do {} while (0) | ||
| 43 | #endif | ||
| 44 | |||
| 45 | struct au1xpsc_audio_dmadata { | ||
| 46 | /* DDMA control data */ | ||
| 47 | unsigned int ddma_id; /* DDMA direction ID for this PSC */ | ||
| 48 | u32 ddma_chan; /* DDMA context */ | ||
| 49 | |||
| 50 | /* PCM context (for irq handlers) */ | ||
| 51 | struct snd_pcm_substream *substream; | ||
| 52 | unsigned long curr_period; /* current segment DDMA is working on */ | ||
| 53 | unsigned long q_period; /* queue period(s) */ | ||
| 54 | unsigned long dma_area; /* address of queued DMA area */ | ||
| 55 | unsigned long dma_area_s; /* start address of DMA area */ | ||
| 56 | unsigned long pos; /* current byte position being played */ | ||
| 57 | unsigned long periods; /* number of SG segments in total */ | ||
| 58 | unsigned long period_bytes; /* size in bytes of one SG segment */ | ||
| 59 | |||
| 60 | /* runtime data */ | ||
| 61 | int msbits; | ||
| 62 | }; | ||
| 63 | |||
| 64 | /* instance data. There can be only one, MacLeod!!!! */ | ||
| 65 | static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2]; | ||
| 66 | |||
| 67 | /* | ||
| 68 | * These settings are somewhat okay, at least on my machine audio plays | ||
| 69 | * almost skip-free. Especially the 64kB buffer seems to help a LOT. | ||
| 70 | */ | ||
| 71 | #define AU1XPSC_PERIOD_MIN_BYTES 1024 | ||
| 72 | #define AU1XPSC_BUFFER_MIN_BYTES 65536 | ||
| 73 | |||
| 74 | #define AU1XPSC_PCM_FMTS \ | ||
| 75 | (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ | ||
| 76 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
| 77 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ | ||
| 78 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \ | ||
| 79 | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \ | ||
| 80 | 0) | ||
| 81 | |||
| 82 | /* PCM hardware DMA capabilities - platform specific */ | ||
| 83 | static const struct snd_pcm_hardware au1xpsc_pcm_hardware = { | ||
| 84 | .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 85 | SNDRV_PCM_INFO_INTERLEAVED, | ||
| 86 | .formats = AU1XPSC_PCM_FMTS, | ||
| 87 | .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES, | ||
| 88 | .period_bytes_max = 4096 * 1024 - 1, | ||
| 89 | .periods_min = 2, | ||
| 90 | .periods_max = 4096, /* 2 to as-much-as-you-like */ | ||
| 91 | .buffer_bytes_max = 4096 * 1024 - 1, | ||
| 92 | .fifo_size = 16, /* fifo entries of AC97/I2S PSC */ | ||
| 93 | }; | ||
| 94 | |||
| 95 | static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) | ||
| 96 | { | ||
| 97 | au1xxx_dbdma_put_source_flags(cd->ddma_chan, | ||
| 98 | (void *)phys_to_virt(cd->dma_area), | ||
| 99 | cd->period_bytes, DDMA_FLAGS_IE); | ||
| 100 | |||
| 101 | /* update next-to-queue period */ | ||
| 102 | ++cd->q_period; | ||
| 103 | cd->dma_area += cd->period_bytes; | ||
| 104 | if (cd->q_period >= cd->periods) { | ||
| 105 | cd->q_period = 0; | ||
| 106 | cd->dma_area = cd->dma_area_s; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) | ||
| 111 | { | ||
| 112 | au1xxx_dbdma_put_dest_flags(cd->ddma_chan, | ||
| 113 | (void *)phys_to_virt(cd->dma_area), | ||
| 114 | cd->period_bytes, DDMA_FLAGS_IE); | ||
| 115 | |||
| 116 | /* update next-to-queue period */ | ||
| 117 | ++cd->q_period; | ||
| 118 | cd->dma_area += cd->period_bytes; | ||
| 119 | if (cd->q_period >= cd->periods) { | ||
| 120 | cd->q_period = 0; | ||
| 121 | cd->dma_area = cd->dma_area_s; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | static void au1x_pcm_dmatx_cb(int irq, void *dev_id) | ||
| 126 | { | ||
| 127 | struct au1xpsc_audio_dmadata *cd = dev_id; | ||
| 128 | |||
| 129 | cd->pos += cd->period_bytes; | ||
| 130 | if (++cd->curr_period >= cd->periods) { | ||
| 131 | cd->pos = 0; | ||
| 132 | cd->curr_period = 0; | ||
| 133 | } | ||
| 134 | snd_pcm_period_elapsed(cd->substream); | ||
| 135 | au1x_pcm_queue_tx(cd); | ||
| 136 | } | ||
| 137 | |||
| 138 | static void au1x_pcm_dmarx_cb(int irq, void *dev_id) | ||
| 139 | { | ||
| 140 | struct au1xpsc_audio_dmadata *cd = dev_id; | ||
| 141 | |||
| 142 | cd->pos += cd->period_bytes; | ||
| 143 | if (++cd->curr_period >= cd->periods) { | ||
| 144 | cd->pos = 0; | ||
| 145 | cd->curr_period = 0; | ||
| 146 | } | ||
| 147 | snd_pcm_period_elapsed(cd->substream); | ||
| 148 | au1x_pcm_queue_rx(cd); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd) | ||
| 152 | { | ||
| 153 | if (pcd->ddma_chan) { | ||
| 154 | au1xxx_dbdma_stop(pcd->ddma_chan); | ||
| 155 | au1xxx_dbdma_reset(pcd->ddma_chan); | ||
| 156 | au1xxx_dbdma_chan_free(pcd->ddma_chan); | ||
| 157 | pcd->ddma_chan = 0; | ||
| 158 | pcd->msbits = 0; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | /* in case of missing DMA ring or changed TX-source / RX-dest bit widths, | ||
| 163 | * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according | ||
| 164 | * to ALSA-supplied sample depth. This is due to limitations in the dbdma api | ||
| 165 | * (cannot adjust source/dest widths of already allocated descriptor ring). | ||
| 166 | */ | ||
| 167 | static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd, | ||
| 168 | int stype, int msbits) | ||
| 169 | { | ||
| 170 | /* DMA only in 8/16/32 bit widths */ | ||
| 171 | if (msbits == 24) | ||
| 172 | msbits = 32; | ||
| 173 | |||
| 174 | /* check current config: correct bits and descriptors allocated? */ | ||
| 175 | if ((pcd->ddma_chan) && (msbits == pcd->msbits)) | ||
| 176 | goto out; /* all ok! */ | ||
| 177 | |||
| 178 | au1x_pcm_dbdma_free(pcd); | ||
| 179 | |||
| 180 | if (stype == PCM_RX) | ||
| 181 | pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id, | ||
| 182 | DSCR_CMD0_ALWAYS, | ||
| 183 | au1x_pcm_dmarx_cb, (void *)pcd); | ||
| 184 | else | ||
| 185 | pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS, | ||
| 186 | pcd->ddma_id, | ||
| 187 | au1x_pcm_dmatx_cb, (void *)pcd); | ||
| 188 | |||
| 189 | if (!pcd->ddma_chan) | ||
| 190 | return -ENOMEM;; | ||
| 191 | |||
| 192 | au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits); | ||
| 193 | au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2); | ||
| 194 | |||
| 195 | pcd->msbits = msbits; | ||
| 196 | |||
| 197 | au1xxx_dbdma_stop(pcd->ddma_chan); | ||
| 198 | au1xxx_dbdma_reset(pcd->ddma_chan); | ||
| 199 | |||
| 200 | out: | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 205 | struct snd_pcm_hw_params *params) | ||
| 206 | { | ||
| 207 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 208 | struct au1xpsc_audio_dmadata *pcd; | ||
| 209 | int stype, ret; | ||
| 210 | |||
| 211 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 212 | if (ret < 0) | ||
| 213 | goto out; | ||
| 214 | |||
| 215 | stype = SUBSTREAM_TYPE(substream); | ||
| 216 | pcd = au1xpsc_audio_pcmdma[stype]; | ||
| 217 | |||
| 218 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " | ||
| 219 | "runtime->min_align %d\n", | ||
| 220 | (unsigned long)runtime->dma_area, | ||
| 221 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, | ||
| 222 | runtime->min_align); | ||
| 223 | |||
| 224 | DBG("bits %d frags %d frag_bytes %d is_rx %d\n", params->msbits, | ||
| 225 | params_periods(params), params_period_bytes(params), stype); | ||
| 226 | |||
| 227 | ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits); | ||
| 228 | if (ret) { | ||
| 229 | MSG("DDMA channel (re)alloc failed!\n"); | ||
| 230 | goto out; | ||
| 231 | } | ||
| 232 | |||
| 233 | pcd->substream = substream; | ||
| 234 | pcd->period_bytes = params_period_bytes(params); | ||
| 235 | pcd->periods = params_periods(params); | ||
| 236 | pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr; | ||
| 237 | pcd->q_period = 0; | ||
| 238 | pcd->curr_period = 0; | ||
| 239 | pcd->pos = 0; | ||
| 240 | |||
| 241 | ret = 0; | ||
| 242 | out: | ||
| 243 | return ret; | ||
| 244 | } | ||
| 245 | |||
| 246 | static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 247 | { | ||
| 248 | snd_pcm_lib_free_pages(substream); | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) | ||
| 253 | { | ||
| 254 | struct au1xpsc_audio_dmadata *pcd = | ||
| 255 | au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]; | ||
| 256 | |||
| 257 | au1xxx_dbdma_reset(pcd->ddma_chan); | ||
| 258 | |||
| 259 | if (SUBSTREAM_TYPE(substream) == PCM_RX) { | ||
| 260 | au1x_pcm_queue_rx(pcd); | ||
| 261 | au1x_pcm_queue_rx(pcd); | ||
| 262 | } else { | ||
| 263 | au1x_pcm_queue_tx(pcd); | ||
| 264 | au1x_pcm_queue_tx(pcd); | ||
| 265 | } | ||
| 266 | |||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 271 | { | ||
| 272 | u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan; | ||
| 273 | |||
| 274 | switch (cmd) { | ||
| 275 | case SNDRV_PCM_TRIGGER_START: | ||
| 276 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 277 | au1xxx_dbdma_start(c); | ||
| 278 | break; | ||
| 279 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 280 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 281 | au1xxx_dbdma_stop(c); | ||
| 282 | break; | ||
| 283 | default: | ||
| 284 | return -EINVAL; | ||
| 285 | } | ||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static snd_pcm_uframes_t | ||
| 290 | au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) | ||
| 291 | { | ||
| 292 | return bytes_to_frames(substream->runtime, | ||
| 293 | au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos); | ||
| 294 | } | ||
| 295 | |||
| 296 | static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) | ||
| 297 | { | ||
| 298 | snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware); | ||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) | ||
| 303 | { | ||
| 304 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]); | ||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | struct snd_pcm_ops au1xpsc_pcm_ops = { | ||
| 309 | .open = au1xpsc_pcm_open, | ||
| 310 | .close = au1xpsc_pcm_close, | ||
| 311 | .ioctl = snd_pcm_lib_ioctl, | ||
| 312 | .hw_params = au1xpsc_pcm_hw_params, | ||
| 313 | .hw_free = au1xpsc_pcm_hw_free, | ||
| 314 | .prepare = au1xpsc_pcm_prepare, | ||
| 315 | .trigger = au1xpsc_pcm_trigger, | ||
| 316 | .pointer = au1xpsc_pcm_pointer, | ||
| 317 | }; | ||
| 318 | |||
| 319 | static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
| 320 | { | ||
| 321 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
| 322 | } | ||
| 323 | |||
| 324 | static int au1xpsc_pcm_new(struct snd_card *card, | ||
| 325 | struct snd_soc_dai *dai, | ||
| 326 | struct snd_pcm *pcm) | ||
| 327 | { | ||
| 328 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
| 329 | card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); | ||
| 330 | |||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | static int au1xpsc_pcm_probe(struct platform_device *pdev) | ||
| 335 | { | ||
| 336 | struct resource *r; | ||
| 337 | int ret; | ||
| 338 | |||
| 339 | if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX]) | ||
| 340 | return -EBUSY; | ||
| 341 | |||
| 342 | /* TX DMA */ | ||
| 343 | au1xpsc_audio_pcmdma[PCM_TX] | ||
| 344 | = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); | ||
| 345 | if (!au1xpsc_audio_pcmdma[PCM_TX]) | ||
| 346 | return -ENOMEM; | ||
| 347 | |||
| 348 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
| 349 | if (!r) { | ||
| 350 | ret = -ENODEV; | ||
| 351 | goto out1; | ||
| 352 | } | ||
| 353 | (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start; | ||
| 354 | |||
| 355 | /* RX DMA */ | ||
| 356 | au1xpsc_audio_pcmdma[PCM_RX] | ||
| 357 | = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); | ||
| 358 | if (!au1xpsc_audio_pcmdma[PCM_RX]) | ||
| 359 | return -ENOMEM; | ||
| 360 | |||
| 361 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
| 362 | if (!r) { | ||
| 363 | ret = -ENODEV; | ||
| 364 | goto out2; | ||
| 365 | } | ||
| 366 | (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start; | ||
| 367 | |||
| 368 | return 0; | ||
| 369 | |||
| 370 | out2: | ||
| 371 | kfree(au1xpsc_audio_pcmdma[PCM_RX]); | ||
| 372 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; | ||
| 373 | out1: | ||
| 374 | kfree(au1xpsc_audio_pcmdma[PCM_TX]); | ||
| 375 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; | ||
| 376 | return ret; | ||
| 377 | } | ||
| 378 | |||
| 379 | static int au1xpsc_pcm_remove(struct platform_device *pdev) | ||
| 380 | { | ||
| 381 | int i; | ||
| 382 | |||
| 383 | for (i = 0; i < 2; i++) { | ||
| 384 | if (au1xpsc_audio_pcmdma[i]) { | ||
| 385 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]); | ||
| 386 | kfree(au1xpsc_audio_pcmdma[i]); | ||
| 387 | au1xpsc_audio_pcmdma[i] = NULL; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | return 0; | ||
| 392 | } | ||
| 393 | |||
| 394 | /* au1xpsc audio platform */ | ||
| 395 | struct snd_soc_platform au1xpsc_soc_platform = { | ||
| 396 | .name = "au1xpsc-pcm-dbdma", | ||
| 397 | .probe = au1xpsc_pcm_probe, | ||
| 398 | .remove = au1xpsc_pcm_remove, | ||
| 399 | .pcm_ops = &au1xpsc_pcm_ops, | ||
| 400 | .pcm_new = au1xpsc_pcm_new, | ||
| 401 | .pcm_free = au1xpsc_pcm_free_dma_buffers, | ||
| 402 | }; | ||
| 403 | EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); | ||
| 404 | |||
| 405 | static int __init au1xpsc_audio_dbdma_init(void) | ||
| 406 | { | ||
| 407 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; | ||
| 408 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; | ||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | static void __exit au1xpsc_audio_dbdma_exit(void) | ||
| 413 | { | ||
| 414 | } | ||
| 415 | |||
| 416 | module_init(au1xpsc_audio_dbdma_init); | ||
| 417 | module_exit(au1xpsc_audio_dbdma_exit); | ||
| 418 | |||
| 419 | MODULE_LICENSE("GPL"); | ||
| 420 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); | ||
| 421 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c new file mode 100644 index 000000000000..57facbad6825 --- /dev/null +++ b/sound/soc/au1x/psc-ac97.c | |||
| @@ -0,0 +1,387 @@ | |||
| 1 | /* | ||
| 2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
| 3 | * | ||
| 4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
| 5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
| 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 | * Au1xxx-PSC AC97 glue. | ||
| 12 | * | ||
| 13 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
| 14 | * of a PSC. Multiple independent audio devices are impossible | ||
| 15 | * with ASoC v1. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/device.h> | ||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/suspend.h> | ||
| 23 | #include <sound/core.h> | ||
| 24 | #include <sound/pcm.h> | ||
| 25 | #include <sound/initval.h> | ||
| 26 | #include <sound/soc.h> | ||
| 27 | #include <asm/mach-au1x00/au1000.h> | ||
| 28 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
| 29 | |||
| 30 | #include "psc.h" | ||
| 31 | |||
| 32 | #define AC97_DIR \ | ||
| 33 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) | ||
| 34 | |||
| 35 | #define AC97_RATES \ | ||
| 36 | SNDRV_PCM_RATE_8000_48000 | ||
| 37 | |||
| 38 | #define AC97_FMTS \ | ||
| 39 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE) | ||
| 40 | |||
| 41 | #define AC97PCR_START(stype) \ | ||
| 42 | ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS) | ||
| 43 | #define AC97PCR_STOP(stype) \ | ||
| 44 | ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP) | ||
| 45 | #define AC97PCR_CLRFIFO(stype) \ | ||
| 46 | ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) | ||
| 47 | |||
| 48 | /* instance data. There can be only one, MacLeod!!!! */ | ||
| 49 | static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; | ||
| 50 | |||
| 51 | /* AC97 controller reads codec register */ | ||
| 52 | static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, | ||
| 53 | unsigned short reg) | ||
| 54 | { | ||
| 55 | /* FIXME */ | ||
| 56 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
| 57 | unsigned short data, tmo; | ||
| 58 | |||
| 59 | au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata)); | ||
| 60 | au_sync(); | ||
| 61 | |||
| 62 | tmo = 1000; | ||
| 63 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) | ||
| 64 | udelay(2); | ||
| 65 | |||
| 66 | if (!tmo) | ||
| 67 | data = 0xffff; | ||
| 68 | else | ||
| 69 | data = au_readl(AC97_CDC(pscdata)) & 0xffff; | ||
| 70 | |||
| 71 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); | ||
| 72 | au_sync(); | ||
| 73 | |||
| 74 | return data; | ||
| 75 | } | ||
| 76 | |||
| 77 | /* AC97 controller writes to codec register */ | ||
| 78 | static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
| 79 | unsigned short val) | ||
| 80 | { | ||
| 81 | /* FIXME */ | ||
| 82 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
| 83 | unsigned int tmo; | ||
| 84 | |||
| 85 | au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata)); | ||
| 86 | au_sync(); | ||
| 87 | tmo = 1000; | ||
| 88 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) | ||
| 89 | au_sync(); | ||
| 90 | |||
| 91 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); | ||
| 92 | au_sync(); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* AC97 controller asserts a warm reset */ | ||
| 96 | static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
| 97 | { | ||
| 98 | /* FIXME */ | ||
| 99 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
| 100 | |||
| 101 | au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); | ||
| 102 | au_sync(); | ||
| 103 | msleep(10); | ||
| 104 | au_writel(0, AC97_RST(pscdata)); | ||
| 105 | au_sync(); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) | ||
| 109 | { | ||
| 110 | /* FIXME */ | ||
| 111 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
| 112 | int i; | ||
| 113 | |||
| 114 | /* disable PSC during cold reset */ | ||
| 115 | au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); | ||
| 116 | au_sync(); | ||
| 117 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); | ||
| 118 | au_sync(); | ||
| 119 | |||
| 120 | /* issue cold reset */ | ||
| 121 | au_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); | ||
| 122 | au_sync(); | ||
| 123 | msleep(500); | ||
| 124 | au_writel(0, AC97_RST(pscdata)); | ||
| 125 | au_sync(); | ||
| 126 | |||
| 127 | /* enable PSC */ | ||
| 128 | au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); | ||
| 129 | au_sync(); | ||
| 130 | |||
| 131 | /* wait for PSC to indicate it's ready */ | ||
| 132 | i = 100000; | ||
| 133 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) | ||
| 134 | au_sync(); | ||
| 135 | |||
| 136 | if (i == 0) { | ||
| 137 | printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n"); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* enable the ac97 function */ | ||
| 142 | au_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
| 143 | au_sync(); | ||
| 144 | |||
| 145 | /* wait for AC97 core to become ready */ | ||
| 146 | i = 100000; | ||
| 147 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) | ||
| 148 | au_sync(); | ||
| 149 | if (i == 0) | ||
| 150 | printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); | ||
| 151 | } | ||
| 152 | |||
| 153 | /* AC97 controller operations */ | ||
| 154 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
| 155 | .read = au1xpsc_ac97_read, | ||
| 156 | .write = au1xpsc_ac97_write, | ||
| 157 | .reset = au1xpsc_ac97_cold_reset, | ||
| 158 | .warm_reset = au1xpsc_ac97_warm_reset, | ||
| 159 | }; | ||
| 160 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
| 161 | |||
| 162 | static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, | ||
| 163 | struct snd_pcm_hw_params *params) | ||
| 164 | { | ||
| 165 | /* FIXME */ | ||
| 166 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
| 167 | unsigned long r, stat; | ||
| 168 | int chans, stype = SUBSTREAM_TYPE(substream); | ||
| 169 | |||
| 170 | chans = params_channels(params); | ||
| 171 | |||
| 172 | r = au_readl(AC97_CFG(pscdata)); | ||
| 173 | stat = au_readl(AC97_STAT(pscdata)); | ||
| 174 | |||
| 175 | /* already active? */ | ||
| 176 | if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) { | ||
| 177 | /* reject parameters not currently set up */ | ||
| 178 | if ((PSC_AC97CFG_GET_LEN(r) != params->msbits) || | ||
| 179 | (pscdata->rate != params_rate(params))) | ||
| 180 | return -EINVAL; | ||
| 181 | } else { | ||
| 182 | /* disable AC97 device controller first */ | ||
| 183 | au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
| 184 | au_sync(); | ||
| 185 | |||
| 186 | /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */ | ||
| 187 | r &= ~PSC_AC97CFG_LEN_MASK; | ||
| 188 | r |= PSC_AC97CFG_SET_LEN(params->msbits); | ||
| 189 | |||
| 190 | /* channels: enable slots for front L/R channel */ | ||
| 191 | if (stype == PCM_TX) { | ||
| 192 | r &= ~PSC_AC97CFG_TXSLOT_MASK; | ||
| 193 | r |= PSC_AC97CFG_TXSLOT_ENA(3); | ||
| 194 | r |= PSC_AC97CFG_TXSLOT_ENA(4); | ||
| 195 | } else { | ||
| 196 | r &= ~PSC_AC97CFG_RXSLOT_MASK; | ||
| 197 | r |= PSC_AC97CFG_RXSLOT_ENA(3); | ||
| 198 | r |= PSC_AC97CFG_RXSLOT_ENA(4); | ||
| 199 | } | ||
| 200 | |||
| 201 | /* finally enable the AC97 controller again */ | ||
| 202 | au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
| 203 | au_sync(); | ||
| 204 | |||
| 205 | pscdata->cfg = r; | ||
| 206 | pscdata->rate = params_rate(params); | ||
| 207 | } | ||
| 208 | |||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, | ||
| 213 | int cmd) | ||
| 214 | { | ||
| 215 | /* FIXME */ | ||
| 216 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
| 217 | int ret, stype = SUBSTREAM_TYPE(substream); | ||
| 218 | |||
| 219 | ret = 0; | ||
| 220 | |||
| 221 | switch (cmd) { | ||
| 222 | case SNDRV_PCM_TRIGGER_START: | ||
| 223 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 224 | au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); | ||
| 225 | au_sync(); | ||
| 226 | break; | ||
| 227 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 228 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 229 | au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); | ||
| 230 | au_sync(); | ||
| 231 | break; | ||
| 232 | default: | ||
| 233 | ret = -EINVAL; | ||
| 234 | } | ||
| 235 | return ret; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int au1xpsc_ac97_probe(struct platform_device *pdev, | ||
| 239 | struct snd_soc_dai *dai) | ||
| 240 | { | ||
| 241 | int ret; | ||
| 242 | struct resource *r; | ||
| 243 | unsigned long sel; | ||
| 244 | |||
| 245 | if (au1xpsc_ac97_workdata) | ||
| 246 | return -EBUSY; | ||
| 247 | |||
| 248 | au1xpsc_ac97_workdata = | ||
| 249 | kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); | ||
| 250 | if (!au1xpsc_ac97_workdata) | ||
| 251 | return -ENOMEM; | ||
| 252 | |||
| 253 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 254 | if (!r) { | ||
| 255 | ret = -ENODEV; | ||
| 256 | goto out0; | ||
| 257 | } | ||
| 258 | |||
| 259 | ret = -EBUSY; | ||
| 260 | au1xpsc_ac97_workdata->ioarea = | ||
| 261 | request_mem_region(r->start, r->end - r->start + 1, | ||
| 262 | "au1xpsc_ac97"); | ||
| 263 | if (!au1xpsc_ac97_workdata->ioarea) | ||
| 264 | goto out0; | ||
| 265 | |||
| 266 | au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff); | ||
| 267 | if (!au1xpsc_ac97_workdata->mmio) | ||
| 268 | goto out1; | ||
| 269 | |||
| 270 | /* configuration: max dma trigger threshold, enable ac97 */ | ||
| 271 | au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | | ||
| 272 | PSC_AC97CFG_TT_FIFO8 | | ||
| 273 | PSC_AC97CFG_DE_ENABLE; | ||
| 274 | |||
| 275 | /* preserve PSC clock source set up by platform (dev.platform_data | ||
| 276 | * is already occupied by soc layer) | ||
| 277 | */ | ||
| 278 | sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK; | ||
| 279 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); | ||
| 280 | au_sync(); | ||
| 281 | au_writel(0, PSC_SEL(au1xpsc_ac97_workdata)); | ||
| 282 | au_sync(); | ||
| 283 | au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata)); | ||
| 284 | au_sync(); | ||
| 285 | /* next up: cold reset. Dont check for PSC-ready now since | ||
| 286 | * there may not be any codec clock yet. | ||
| 287 | */ | ||
| 288 | |||
| 289 | return 0; | ||
| 290 | |||
| 291 | out1: | ||
| 292 | release_resource(au1xpsc_ac97_workdata->ioarea); | ||
| 293 | kfree(au1xpsc_ac97_workdata->ioarea); | ||
| 294 | out0: | ||
| 295 | kfree(au1xpsc_ac97_workdata); | ||
| 296 | au1xpsc_ac97_workdata = NULL; | ||
| 297 | return ret; | ||
| 298 | } | ||
| 299 | |||
| 300 | static void au1xpsc_ac97_remove(struct platform_device *pdev, | ||
| 301 | struct snd_soc_dai *dai) | ||
| 302 | { | ||
| 303 | /* disable PSC completely */ | ||
| 304 | au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); | ||
| 305 | au_sync(); | ||
| 306 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); | ||
| 307 | au_sync(); | ||
| 308 | |||
| 309 | iounmap(au1xpsc_ac97_workdata->mmio); | ||
| 310 | release_resource(au1xpsc_ac97_workdata->ioarea); | ||
| 311 | kfree(au1xpsc_ac97_workdata->ioarea); | ||
| 312 | kfree(au1xpsc_ac97_workdata); | ||
| 313 | au1xpsc_ac97_workdata = NULL; | ||
| 314 | } | ||
| 315 | |||
| 316 | static int au1xpsc_ac97_suspend(struct platform_device *pdev, | ||
| 317 | struct snd_soc_dai *dai) | ||
| 318 | { | ||
| 319 | /* save interesting registers and disable PSC */ | ||
| 320 | au1xpsc_ac97_workdata->pm[0] = | ||
| 321 | au_readl(PSC_SEL(au1xpsc_ac97_workdata)); | ||
| 322 | |||
| 323 | au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); | ||
| 324 | au_sync(); | ||
| 325 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); | ||
| 326 | au_sync(); | ||
| 327 | |||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | static int au1xpsc_ac97_resume(struct platform_device *pdev, | ||
| 332 | struct snd_soc_dai *dai) | ||
| 333 | { | ||
| 334 | /* restore PSC clock config */ | ||
| 335 | au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, | ||
| 336 | PSC_SEL(au1xpsc_ac97_workdata)); | ||
| 337 | au_sync(); | ||
| 338 | |||
| 339 | /* after this point the ac97 core will cold-reset the codec. | ||
| 340 | * During cold-reset the PSC is reinitialized and the last | ||
| 341 | * configuration set up in hw_params() is restored. | ||
| 342 | */ | ||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | struct snd_soc_dai au1xpsc_ac97_dai = { | ||
| 347 | .name = "au1xpsc_ac97", | ||
| 348 | .type = SND_SOC_DAI_AC97, | ||
| 349 | .probe = au1xpsc_ac97_probe, | ||
| 350 | .remove = au1xpsc_ac97_remove, | ||
| 351 | .suspend = au1xpsc_ac97_suspend, | ||
| 352 | .resume = au1xpsc_ac97_resume, | ||
| 353 | .playback = { | ||
| 354 | .rates = AC97_RATES, | ||
| 355 | .formats = AC97_FMTS, | ||
| 356 | .channels_min = 2, | ||
| 357 | .channels_max = 2, | ||
| 358 | }, | ||
| 359 | .capture = { | ||
| 360 | .rates = AC97_RATES, | ||
| 361 | .formats = AC97_FMTS, | ||
| 362 | .channels_min = 2, | ||
| 363 | .channels_max = 2, | ||
| 364 | }, | ||
| 365 | .ops = { | ||
| 366 | .trigger = au1xpsc_ac97_trigger, | ||
| 367 | .hw_params = au1xpsc_ac97_hw_params, | ||
| 368 | }, | ||
| 369 | }; | ||
| 370 | EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); | ||
| 371 | |||
| 372 | static int __init au1xpsc_ac97_init(void) | ||
| 373 | { | ||
| 374 | au1xpsc_ac97_workdata = NULL; | ||
| 375 | return 0; | ||
| 376 | } | ||
| 377 | |||
| 378 | static void __exit au1xpsc_ac97_exit(void) | ||
| 379 | { | ||
| 380 | } | ||
| 381 | |||
| 382 | module_init(au1xpsc_ac97_init); | ||
| 383 | module_exit(au1xpsc_ac97_exit); | ||
| 384 | |||
| 385 | MODULE_LICENSE("GPL"); | ||
| 386 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver"); | ||
| 387 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c new file mode 100644 index 000000000000..ba4b5c199f21 --- /dev/null +++ b/sound/soc/au1x/psc-i2s.c | |||
| @@ -0,0 +1,414 @@ | |||
| 1 | /* | ||
| 2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
| 3 | * | ||
| 4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
| 5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
| 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 | * Au1xxx-PSC I2S glue. | ||
| 12 | * | ||
| 13 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
| 14 | * of a PSC. Multiple independent audio devices are impossible | ||
| 15 | * with ASoC v1. | ||
| 16 | * NOTE: so far only PSC slave mode (bit- and frameclock) is supported. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/suspend.h> | ||
| 22 | #include <sound/core.h> | ||
| 23 | #include <sound/pcm.h> | ||
| 24 | #include <sound/initval.h> | ||
| 25 | #include <sound/soc.h> | ||
| 26 | #include <asm/mach-au1x00/au1000.h> | ||
| 27 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
| 28 | |||
| 29 | #include "psc.h" | ||
| 30 | |||
| 31 | /* supported I2S DAI hardware formats */ | ||
| 32 | #define AU1XPSC_I2S_DAIFMT \ | ||
| 33 | (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | \ | ||
| 34 | SND_SOC_DAIFMT_NB_NF) | ||
| 35 | |||
| 36 | /* supported I2S direction */ | ||
| 37 | #define AU1XPSC_I2S_DIR \ | ||
| 38 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) | ||
| 39 | |||
| 40 | #define AU1XPSC_I2S_RATES \ | ||
| 41 | SNDRV_PCM_RATE_8000_192000 | ||
| 42 | |||
| 43 | #define AU1XPSC_I2S_FMTS \ | ||
| 44 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
| 45 | |||
| 46 | #define I2SSTAT_BUSY(stype) \ | ||
| 47 | ((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB) | ||
| 48 | #define I2SPCR_START(stype) \ | ||
| 49 | ((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS) | ||
| 50 | #define I2SPCR_STOP(stype) \ | ||
| 51 | ((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP) | ||
| 52 | #define I2SPCR_CLRFIFO(stype) \ | ||
| 53 | ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC) | ||
| 54 | |||
| 55 | |||
| 56 | /* instance data. There can be only one, MacLeod!!!! */ | ||
| 57 | static struct au1xpsc_audio_data *au1xpsc_i2s_workdata; | ||
| 58 | |||
| 59 | static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
| 60 | unsigned int fmt) | ||
| 61 | { | ||
| 62 | struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; | ||
| 63 | unsigned long ct; | ||
| 64 | int ret; | ||
| 65 | |||
| 66 | ret = -EINVAL; | ||
| 67 | |||
| 68 | ct = pscdata->cfg; | ||
| 69 | |||
| 70 | ct &= ~(PSC_I2SCFG_XM | PSC_I2SCFG_MLJ); /* left-justified */ | ||
| 71 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 72 | case SND_SOC_DAIFMT_I2S: | ||
| 73 | ct |= PSC_I2SCFG_XM; /* enable I2S mode */ | ||
| 74 | break; | ||
| 75 | case SND_SOC_DAIFMT_MSB: | ||
| 76 | break; | ||
| 77 | case SND_SOC_DAIFMT_LSB: | ||
| 78 | ct |= PSC_I2SCFG_MLJ; /* LSB (right-) justified */ | ||
| 79 | break; | ||
| 80 | default: | ||
| 81 | goto out; | ||
| 82 | } | ||
| 83 | |||
| 84 | ct &= ~(PSC_I2SCFG_BI | PSC_I2SCFG_WI); /* IB-IF */ | ||
| 85 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
| 86 | case SND_SOC_DAIFMT_NB_NF: | ||
| 87 | ct |= PSC_I2SCFG_BI | PSC_I2SCFG_WI; | ||
| 88 | break; | ||
| 89 | case SND_SOC_DAIFMT_NB_IF: | ||
| 90 | ct |= PSC_I2SCFG_BI; | ||
| 91 | break; | ||
| 92 | case SND_SOC_DAIFMT_IB_NF: | ||
| 93 | ct |= PSC_I2SCFG_WI; | ||
| 94 | break; | ||
| 95 | case SND_SOC_DAIFMT_IB_IF: | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | goto out; | ||
| 99 | } | ||
| 100 | |||
| 101 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 102 | case SND_SOC_DAIFMT_CBM_CFM: /* CODEC master */ | ||
| 103 | ct |= PSC_I2SCFG_MS; /* PSC I2S slave mode */ | ||
| 104 | break; | ||
| 105 | case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */ | ||
| 106 | ct &= ~PSC_I2SCFG_MS; /* PSC I2S Master mode */ | ||
| 107 | break; | ||
| 108 | default: | ||
| 109 | goto out; | ||
| 110 | } | ||
| 111 | |||
| 112 | pscdata->cfg = ct; | ||
| 113 | ret = 0; | ||
| 114 | out: | ||
| 115 | return ret; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, | ||
| 119 | struct snd_pcm_hw_params *params) | ||
| 120 | { | ||
| 121 | struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; | ||
| 122 | |||
| 123 | int cfgbits; | ||
| 124 | unsigned long stat; | ||
| 125 | |||
| 126 | /* check if the PSC is already streaming data */ | ||
| 127 | stat = au_readl(I2S_STAT(pscdata)); | ||
| 128 | if (stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB)) { | ||
| 129 | /* reject parameters not currently set up in hardware */ | ||
| 130 | cfgbits = au_readl(I2S_CFG(pscdata)); | ||
| 131 | if ((PSC_I2SCFG_GET_LEN(cfgbits) != params->msbits) || | ||
| 132 | (params_rate(params) != pscdata->rate)) | ||
| 133 | return -EINVAL; | ||
| 134 | } else { | ||
| 135 | /* set sample bitdepth */ | ||
| 136 | pscdata->cfg &= ~(0x1f << 4); | ||
| 137 | pscdata->cfg |= PSC_I2SCFG_SET_LEN(params->msbits); | ||
| 138 | /* remember current rate for other stream */ | ||
| 139 | pscdata->rate = params_rate(params); | ||
| 140 | } | ||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | /* Configure PSC late: on my devel systems the codec is I2S master and | ||
| 145 | * supplies the i2sbitclock __AND__ i2sMclk (!) to the PSC unit. ASoC | ||
| 146 | * uses aggressive PM and switches the codec off when it is not in use | ||
| 147 | * which also means the PSC unit doesn't get any clocks and is therefore | ||
| 148 | * dead. That's why this chunk here gets called from the trigger callback | ||
| 149 | * because I can be reasonably certain the codec is driving the clocks. | ||
| 150 | */ | ||
| 151 | static int au1xpsc_i2s_configure(struct au1xpsc_audio_data *pscdata) | ||
| 152 | { | ||
| 153 | unsigned long tmo; | ||
| 154 | |||
| 155 | /* bring PSC out of sleep, and configure I2S unit */ | ||
| 156 | au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); | ||
| 157 | au_sync(); | ||
| 158 | |||
| 159 | tmo = 1000000; | ||
| 160 | while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo) | ||
| 161 | tmo--; | ||
| 162 | |||
| 163 | if (!tmo) | ||
| 164 | goto psc_err; | ||
| 165 | |||
| 166 | au_writel(0, I2S_CFG(pscdata)); | ||
| 167 | au_sync(); | ||
| 168 | au_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata)); | ||
| 169 | au_sync(); | ||
| 170 | |||
| 171 | /* wait for I2S controller to become ready */ | ||
| 172 | tmo = 1000000; | ||
| 173 | while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo) | ||
| 174 | tmo--; | ||
| 175 | |||
| 176 | if (tmo) | ||
| 177 | return 0; | ||
| 178 | |||
| 179 | psc_err: | ||
| 180 | au_writel(0, I2S_CFG(pscdata)); | ||
| 181 | au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); | ||
| 182 | au_sync(); | ||
| 183 | return -ETIMEDOUT; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int au1xpsc_i2s_start(struct au1xpsc_audio_data *pscdata, int stype) | ||
| 187 | { | ||
| 188 | unsigned long tmo, stat; | ||
| 189 | int ret; | ||
| 190 | |||
| 191 | ret = 0; | ||
| 192 | |||
| 193 | /* if both TX and RX are idle, configure the PSC */ | ||
| 194 | stat = au_readl(I2S_STAT(pscdata)); | ||
| 195 | if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) { | ||
| 196 | ret = au1xpsc_i2s_configure(pscdata); | ||
| 197 | if (ret) | ||
| 198 | goto out; | ||
| 199 | } | ||
| 200 | |||
| 201 | au_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata)); | ||
| 202 | au_sync(); | ||
| 203 | au_writel(I2SPCR_START(stype), I2S_PCR(pscdata)); | ||
| 204 | au_sync(); | ||
| 205 | |||
| 206 | /* wait for start confirmation */ | ||
| 207 | tmo = 1000000; | ||
| 208 | while (!(au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) | ||
| 209 | tmo--; | ||
| 210 | |||
| 211 | if (!tmo) { | ||
| 212 | au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); | ||
| 213 | au_sync(); | ||
| 214 | ret = -ETIMEDOUT; | ||
| 215 | } | ||
| 216 | out: | ||
| 217 | return ret; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) | ||
| 221 | { | ||
| 222 | unsigned long tmo, stat; | ||
| 223 | |||
| 224 | au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); | ||
| 225 | au_sync(); | ||
| 226 | |||
| 227 | /* wait for stop confirmation */ | ||
| 228 | tmo = 1000000; | ||
| 229 | while ((au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) | ||
| 230 | tmo--; | ||
| 231 | |||
| 232 | /* if both TX and RX are idle, disable PSC */ | ||
| 233 | stat = au_readl(I2S_STAT(pscdata)); | ||
| 234 | if (!(stat & (PSC_I2SSTAT_RB | PSC_I2SSTAT_RB))) { | ||
| 235 | au_writel(0, I2S_CFG(pscdata)); | ||
| 236 | au_sync(); | ||
| 237 | au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); | ||
| 238 | au_sync(); | ||
| 239 | } | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 244 | { | ||
| 245 | struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; | ||
| 246 | int ret, stype = SUBSTREAM_TYPE(substream); | ||
| 247 | |||
| 248 | switch (cmd) { | ||
| 249 | case SNDRV_PCM_TRIGGER_START: | ||
| 250 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 251 | ret = au1xpsc_i2s_start(pscdata, stype); | ||
| 252 | break; | ||
| 253 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 254 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 255 | ret = au1xpsc_i2s_stop(pscdata, stype); | ||
| 256 | break; | ||
| 257 | default: | ||
| 258 | ret = -EINVAL; | ||
| 259 | } | ||
| 260 | return ret; | ||
| 261 | } | ||
| 262 | |||
| 263 | static int au1xpsc_i2s_probe(struct platform_device *pdev, | ||
| 264 | struct snd_soc_dai *dai) | ||
| 265 | { | ||
| 266 | struct resource *r; | ||
| 267 | unsigned long sel; | ||
| 268 | int ret; | ||
| 269 | |||
| 270 | if (au1xpsc_i2s_workdata) | ||
| 271 | return -EBUSY; | ||
| 272 | |||
| 273 | au1xpsc_i2s_workdata = | ||
| 274 | kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); | ||
| 275 | if (!au1xpsc_i2s_workdata) | ||
| 276 | return -ENOMEM; | ||
| 277 | |||
| 278 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 279 | if (!r) { | ||
| 280 | ret = -ENODEV; | ||
| 281 | goto out0; | ||
| 282 | } | ||
| 283 | |||
| 284 | ret = -EBUSY; | ||
| 285 | au1xpsc_i2s_workdata->ioarea = | ||
| 286 | request_mem_region(r->start, r->end - r->start + 1, | ||
| 287 | "au1xpsc_i2s"); | ||
| 288 | if (!au1xpsc_i2s_workdata->ioarea) | ||
| 289 | goto out0; | ||
| 290 | |||
| 291 | au1xpsc_i2s_workdata->mmio = ioremap(r->start, 0xffff); | ||
| 292 | if (!au1xpsc_i2s_workdata->mmio) | ||
| 293 | goto out1; | ||
| 294 | |||
| 295 | /* preserve PSC clock source set up by platform (dev.platform_data | ||
| 296 | * is already occupied by soc layer) | ||
| 297 | */ | ||
| 298 | sel = au_readl(PSC_SEL(au1xpsc_i2s_workdata)) & PSC_SEL_CLK_MASK; | ||
| 299 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
| 300 | au_sync(); | ||
| 301 | au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(au1xpsc_i2s_workdata)); | ||
| 302 | au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); | ||
| 303 | au_sync(); | ||
| 304 | |||
| 305 | /* preconfigure: set max rx/tx fifo depths */ | ||
| 306 | au1xpsc_i2s_workdata->cfg |= | ||
| 307 | PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8; | ||
| 308 | |||
| 309 | /* don't wait for I2S core to become ready now; clocks may not | ||
| 310 | * be running yet; depending on clock input for PSC a wait might | ||
| 311 | * time out. | ||
| 312 | */ | ||
| 313 | |||
| 314 | return 0; | ||
| 315 | |||
| 316 | out1: | ||
| 317 | release_resource(au1xpsc_i2s_workdata->ioarea); | ||
| 318 | kfree(au1xpsc_i2s_workdata->ioarea); | ||
| 319 | out0: | ||
| 320 | kfree(au1xpsc_i2s_workdata); | ||
| 321 | au1xpsc_i2s_workdata = NULL; | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | |||
| 325 | static void au1xpsc_i2s_remove(struct platform_device *pdev, | ||
| 326 | struct snd_soc_dai *dai) | ||
| 327 | { | ||
| 328 | au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); | ||
| 329 | au_sync(); | ||
| 330 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
| 331 | au_sync(); | ||
| 332 | |||
| 333 | iounmap(au1xpsc_i2s_workdata->mmio); | ||
| 334 | release_resource(au1xpsc_i2s_workdata->ioarea); | ||
| 335 | kfree(au1xpsc_i2s_workdata->ioarea); | ||
| 336 | kfree(au1xpsc_i2s_workdata); | ||
| 337 | au1xpsc_i2s_workdata = NULL; | ||
| 338 | } | ||
| 339 | |||
| 340 | static int au1xpsc_i2s_suspend(struct platform_device *pdev, | ||
| 341 | struct snd_soc_dai *cpu_dai) | ||
| 342 | { | ||
| 343 | /* save interesting register and disable PSC */ | ||
| 344 | au1xpsc_i2s_workdata->pm[0] = | ||
| 345 | au_readl(PSC_SEL(au1xpsc_i2s_workdata)); | ||
| 346 | |||
| 347 | au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); | ||
| 348 | au_sync(); | ||
| 349 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
| 350 | au_sync(); | ||
| 351 | |||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | |||
| 355 | static int au1xpsc_i2s_resume(struct platform_device *pdev, | ||
| 356 | struct snd_soc_dai *cpu_dai) | ||
| 357 | { | ||
| 358 | /* select I2S mode and PSC clock */ | ||
| 359 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
| 360 | au_sync(); | ||
| 361 | au_writel(0, PSC_SEL(au1xpsc_i2s_workdata)); | ||
| 362 | au_sync(); | ||
| 363 | au_writel(au1xpsc_i2s_workdata->pm[0], | ||
| 364 | PSC_SEL(au1xpsc_i2s_workdata)); | ||
| 365 | au_sync(); | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | struct snd_soc_dai au1xpsc_i2s_dai = { | ||
| 371 | .name = "au1xpsc_i2s", | ||
| 372 | .type = SND_SOC_DAI_I2S, | ||
| 373 | .probe = au1xpsc_i2s_probe, | ||
| 374 | .remove = au1xpsc_i2s_remove, | ||
| 375 | .suspend = au1xpsc_i2s_suspend, | ||
| 376 | .resume = au1xpsc_i2s_resume, | ||
| 377 | .playback = { | ||
| 378 | .rates = AU1XPSC_I2S_RATES, | ||
| 379 | .formats = AU1XPSC_I2S_FMTS, | ||
| 380 | .channels_min = 2, | ||
| 381 | .channels_max = 8, /* 2 without external help */ | ||
| 382 | }, | ||
| 383 | .capture = { | ||
| 384 | .rates = AU1XPSC_I2S_RATES, | ||
| 385 | .formats = AU1XPSC_I2S_FMTS, | ||
| 386 | .channels_min = 2, | ||
| 387 | .channels_max = 8, /* 2 without external help */ | ||
| 388 | }, | ||
| 389 | .ops = { | ||
| 390 | .trigger = au1xpsc_i2s_trigger, | ||
| 391 | .hw_params = au1xpsc_i2s_hw_params, | ||
| 392 | }, | ||
| 393 | .dai_ops = { | ||
| 394 | .set_fmt = au1xpsc_i2s_set_fmt, | ||
| 395 | }, | ||
| 396 | }; | ||
| 397 | EXPORT_SYMBOL(au1xpsc_i2s_dai); | ||
| 398 | |||
| 399 | static int __init au1xpsc_i2s_init(void) | ||
| 400 | { | ||
| 401 | au1xpsc_i2s_workdata = NULL; | ||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | static void __exit au1xpsc_i2s_exit(void) | ||
| 406 | { | ||
| 407 | } | ||
| 408 | |||
| 409 | module_init(au1xpsc_i2s_init); | ||
| 410 | module_exit(au1xpsc_i2s_exit); | ||
| 411 | |||
| 412 | MODULE_LICENSE("GPL"); | ||
| 413 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver"); | ||
| 414 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h new file mode 100644 index 000000000000..8fdb1a04a07b --- /dev/null +++ b/sound/soc/au1x/psc.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
| 3 | * | ||
| 4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
| 5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
| 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 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
| 12 | * of a PSC. Multiple independent audio devices are impossible | ||
| 13 | * with ASoC v1. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef _AU1X_PCM_H | ||
| 17 | #define _AU1X_PCM_H | ||
| 18 | |||
| 19 | extern struct snd_soc_dai au1xpsc_ac97_dai; | ||
| 20 | extern struct snd_soc_dai au1xpsc_i2s_dai; | ||
| 21 | extern struct snd_soc_platform au1xpsc_soc_platform; | ||
| 22 | extern struct snd_ac97_bus_ops soc_ac97_ops; | ||
| 23 | |||
| 24 | struct au1xpsc_audio_data { | ||
| 25 | void __iomem *mmio; | ||
| 26 | |||
| 27 | unsigned long cfg; | ||
| 28 | unsigned long rate; | ||
| 29 | |||
| 30 | unsigned long pm[2]; | ||
| 31 | struct resource *ioarea; | ||
| 32 | }; | ||
| 33 | |||
| 34 | #define PCM_TX 0 | ||
| 35 | #define PCM_RX 1 | ||
| 36 | |||
| 37 | #define SUBSTREAM_TYPE(substream) \ | ||
| 38 | ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) | ||
| 39 | |||
| 40 | /* easy access macros */ | ||
| 41 | #define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET) | ||
| 42 | #define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET) | ||
| 43 | #define I2S_STAT(x) ((unsigned long)((x)->mmio) + PSC_I2SSTAT_OFFSET) | ||
| 44 | #define I2S_CFG(x) ((unsigned long)((x)->mmio) + PSC_I2SCFG_OFFSET) | ||
| 45 | #define I2S_PCR(x) ((unsigned long)((x)->mmio) + PSC_I2SPCR_OFFSET) | ||
| 46 | #define AC97_CFG(x) ((unsigned long)((x)->mmio) + PSC_AC97CFG_OFFSET) | ||
| 47 | #define AC97_CDC(x) ((unsigned long)((x)->mmio) + PSC_AC97CDC_OFFSET) | ||
| 48 | #define AC97_EVNT(x) ((unsigned long)((x)->mmio) + PSC_AC97EVNT_OFFSET) | ||
| 49 | #define AC97_PCR(x) ((unsigned long)((x)->mmio) + PSC_AC97PCR_OFFSET) | ||
| 50 | #define AC97_RST(x) ((unsigned long)((x)->mmio) + PSC_AC97RST_OFFSET) | ||
| 51 | #define AC97_STAT(x) ((unsigned long)((x)->mmio) + PSC_AC97STAT_OFFSET) | ||
| 52 | |||
| 53 | #endif | ||
diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c new file mode 100644 index 000000000000..f75ae7f62c3d --- /dev/null +++ b/sound/soc/au1x/sample-ac97.c | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | /* | ||
| 2 | * Sample Au12x0/Au1550 PSC AC97 sound machine. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007-2008 Manuel Lauss <mano@roarinelk.homelinux.net> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms outlined in the file COPYING at the root of this | ||
| 8 | * source archive. | ||
| 9 | * | ||
| 10 | * This is a very generic AC97 sound machine driver for boards which | ||
| 11 | * have (AC97) audio at PSC1 (e.g. DB1200 demoboards). | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/moduleparam.h> | ||
| 16 | #include <linux/timer.h> | ||
| 17 | #include <linux/interrupt.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <sound/core.h> | ||
| 20 | #include <sound/pcm.h> | ||
| 21 | #include <sound/soc.h> | ||
| 22 | #include <sound/soc-dapm.h> | ||
| 23 | #include <asm/mach-au1x00/au1000.h> | ||
| 24 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
| 25 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | ||
| 26 | |||
| 27 | #include "../codecs/ac97.h" | ||
| 28 | #include "psc.h" | ||
| 29 | |||
| 30 | static int au1xpsc_sample_ac97_init(struct snd_soc_codec *codec) | ||
| 31 | { | ||
| 32 | snd_soc_dapm_sync(codec); | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { | ||
| 37 | .name = "AC97", | ||
| 38 | .stream_name = "AC97 HiFi", | ||
| 39 | .cpu_dai = &au1xpsc_ac97_dai, /* see psc-ac97.c */ | ||
| 40 | .codec_dai = &ac97_dai, /* see codecs/ac97.c */ | ||
| 41 | .init = au1xpsc_sample_ac97_init, | ||
| 42 | .ops = NULL, | ||
| 43 | }; | ||
| 44 | |||
| 45 | static struct snd_soc_machine au1xpsc_sample_ac97_machine = { | ||
| 46 | .name = "Au1xxx PSC AC97 Audio", | ||
| 47 | .dai_link = &au1xpsc_sample_ac97_dai, | ||
| 48 | .num_links = 1, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct snd_soc_device au1xpsc_sample_ac97_devdata = { | ||
| 52 | .machine = &au1xpsc_sample_ac97_machine, | ||
| 53 | .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ | ||
| 54 | .codec_dev = &soc_codec_dev_ac97, | ||
| 55 | }; | ||
| 56 | |||
| 57 | static struct resource au1xpsc_psc1_res[] = { | ||
| 58 | [0] = { | ||
| 59 | .start = CPHYSADDR(PSC1_BASE_ADDR), | ||
| 60 | .end = CPHYSADDR(PSC1_BASE_ADDR) + 0x000fffff, | ||
| 61 | .flags = IORESOURCE_MEM, | ||
| 62 | }, | ||
| 63 | [1] = { | ||
| 64 | #ifdef CONFIG_SOC_AU1200 | ||
| 65 | .start = AU1200_PSC1_INT, | ||
| 66 | .end = AU1200_PSC1_INT, | ||
| 67 | #elif defined(CONFIG_SOC_AU1550) | ||
| 68 | .start = AU1550_PSC1_INT, | ||
| 69 | .end = AU1550_PSC1_INT, | ||
| 70 | #endif | ||
| 71 | .flags = IORESOURCE_IRQ, | ||
| 72 | }, | ||
| 73 | [2] = { | ||
| 74 | .start = DSCR_CMD0_PSC1_TX, | ||
| 75 | .end = DSCR_CMD0_PSC1_TX, | ||
| 76 | .flags = IORESOURCE_DMA, | ||
| 77 | }, | ||
| 78 | [3] = { | ||
| 79 | .start = DSCR_CMD0_PSC1_RX, | ||
| 80 | .end = DSCR_CMD0_PSC1_RX, | ||
| 81 | .flags = IORESOURCE_DMA, | ||
| 82 | }, | ||
| 83 | }; | ||
| 84 | |||
| 85 | static struct platform_device *au1xpsc_sample_ac97_dev; | ||
| 86 | |||
| 87 | static int __init au1xpsc_sample_ac97_load(void) | ||
| 88 | { | ||
| 89 | int ret; | ||
| 90 | |||
| 91 | #ifdef CONFIG_SOC_AU1200 | ||
| 92 | unsigned long io; | ||
| 93 | |||
| 94 | /* modify sys_pinfunc for AC97 on PSC1 */ | ||
| 95 | io = au_readl(SYS_PINFUNC); | ||
| 96 | io |= SYS_PINFUNC_P1C; | ||
| 97 | io &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B); | ||
| 98 | au_writel(io, SYS_PINFUNC); | ||
| 99 | au_sync(); | ||
| 100 | #endif | ||
| 101 | |||
| 102 | ret = -ENOMEM; | ||
| 103 | |||
| 104 | /* setup PSC clock source for AC97 part: external clock provided | ||
| 105 | * by codec. The psc-ac97.c driver depends on this setting! | ||
| 106 | */ | ||
| 107 | au_writel(PSC_SEL_CLK_SERCLK, PSC1_BASE_ADDR + PSC_SEL_OFFSET); | ||
| 108 | au_sync(); | ||
| 109 | |||
| 110 | au1xpsc_sample_ac97_dev = platform_device_alloc("soc-audio", -1); | ||
| 111 | if (!au1xpsc_sample_ac97_dev) | ||
| 112 | goto out; | ||
| 113 | |||
| 114 | au1xpsc_sample_ac97_dev->resource = | ||
| 115 | kmemdup(au1xpsc_psc1_res, sizeof(struct resource) * | ||
| 116 | ARRAY_SIZE(au1xpsc_psc1_res), GFP_KERNEL); | ||
| 117 | au1xpsc_sample_ac97_dev->num_resources = ARRAY_SIZE(au1xpsc_psc1_res); | ||
| 118 | au1xpsc_sample_ac97_dev->id = 1; | ||
| 119 | |||
| 120 | platform_set_drvdata(au1xpsc_sample_ac97_dev, | ||
| 121 | &au1xpsc_sample_ac97_devdata); | ||
| 122 | au1xpsc_sample_ac97_devdata.dev = &au1xpsc_sample_ac97_dev->dev; | ||
| 123 | ret = platform_device_add(au1xpsc_sample_ac97_dev); | ||
| 124 | |||
| 125 | if (ret) { | ||
| 126 | platform_device_put(au1xpsc_sample_ac97_dev); | ||
| 127 | au1xpsc_sample_ac97_dev = NULL; | ||
| 128 | } | ||
| 129 | |||
| 130 | out: | ||
| 131 | return ret; | ||
| 132 | } | ||
| 133 | |||
| 134 | static void __exit au1xpsc_sample_ac97_exit(void) | ||
| 135 | { | ||
| 136 | platform_device_unregister(au1xpsc_sample_ac97_dev); | ||
| 137 | } | ||
| 138 | |||
| 139 | module_init(au1xpsc_sample_ac97_load); | ||
| 140 | module_exit(au1xpsc_sample_ac97_exit); | ||
| 141 | |||
| 142 | MODULE_LICENSE("GPL"); | ||
| 143 | MODULE_DESCRIPTION("Au1xxx PSC sample AC97 machine"); | ||
| 144 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3903ab7dfa4a..1db04a28a53d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
| @@ -1,31 +1,37 @@ | |||
| 1 | config SND_SOC_AC97_CODEC | 1 | config SND_SOC_AC97_CODEC |
| 2 | tristate | 2 | tristate |
| 3 | depends on SND_SOC | 3 | select SND_AC97_CODEC |
| 4 | |||
| 5 | config SND_SOC_AK4535 | ||
| 6 | tristate | ||
| 7 | |||
| 8 | config SND_SOC_UDA1380 | ||
| 9 | tristate | ||
| 10 | |||
| 11 | config SND_SOC_WM8510 | ||
| 12 | tristate | ||
| 4 | 13 | ||
| 5 | config SND_SOC_WM8731 | 14 | config SND_SOC_WM8731 |
| 6 | tristate | 15 | tristate |
| 7 | depends on SND_SOC | ||
| 8 | 16 | ||
| 9 | config SND_SOC_WM8750 | 17 | config SND_SOC_WM8750 |
| 10 | tristate | 18 | tristate |
| 11 | depends on SND_SOC | ||
| 12 | 19 | ||
| 13 | config SND_SOC_WM8753 | 20 | config SND_SOC_WM8753 |
| 14 | tristate | 21 | tristate |
| 15 | depends on SND_SOC | 22 | |
| 23 | config SND_SOC_WM8990 | ||
| 24 | tristate | ||
| 16 | 25 | ||
| 17 | config SND_SOC_WM9712 | 26 | config SND_SOC_WM9712 |
| 18 | tristate | 27 | tristate |
| 19 | depends on SND_SOC | ||
| 20 | 28 | ||
| 21 | config SND_SOC_WM9713 | 29 | config SND_SOC_WM9713 |
| 22 | tristate | 30 | tristate |
| 23 | depends on SND_SOC | ||
| 24 | 31 | ||
| 25 | # Cirrus Logic CS4270 Codec | 32 | # Cirrus Logic CS4270 Codec |
| 26 | config SND_SOC_CS4270 | 33 | config SND_SOC_CS4270 |
| 27 | tristate | 34 | tristate |
| 28 | depends on SND_SOC | ||
| 29 | 35 | ||
| 30 | # Cirrus Logic CS4270 Codec Hardware Mute Support | 36 | # Cirrus Logic CS4270 Codec Hardware Mute Support |
| 31 | # Select if you have external muting circuitry attached to your CS4270. | 37 | # Select if you have external muting circuitry attached to your CS4270. |
| @@ -43,4 +49,4 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
| 43 | 49 | ||
| 44 | config SND_SOC_TLV320AIC3X | 50 | config SND_SOC_TLV320AIC3X |
| 45 | tristate | 51 | tristate |
| 46 | depends on SND_SOC && I2C | 52 | depends on I2C |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4e1314c9d3ec..d7b97abcf729 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
| @@ -1,16 +1,24 @@ | |||
| 1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
| 2 | snd-soc-ak4535-objs := ak4535.o | ||
| 3 | snd-soc-uda1380-objs := uda1380.o | ||
| 4 | snd-soc-wm8510-objs := wm8510.o | ||
| 2 | snd-soc-wm8731-objs := wm8731.o | 5 | snd-soc-wm8731-objs := wm8731.o |
| 3 | snd-soc-wm8750-objs := wm8750.o | 6 | snd-soc-wm8750-objs := wm8750.o |
| 4 | snd-soc-wm8753-objs := wm8753.o | 7 | snd-soc-wm8753-objs := wm8753.o |
| 8 | snd-soc-wm8990-objs := wm8990.o | ||
| 5 | snd-soc-wm9712-objs := wm9712.o | 9 | snd-soc-wm9712-objs := wm9712.o |
| 6 | snd-soc-wm9713-objs := wm9713.o | 10 | snd-soc-wm9713-objs := wm9713.o |
| 7 | snd-soc-cs4270-objs := cs4270.o | 11 | snd-soc-cs4270-objs := cs4270.o |
| 8 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 12 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
| 9 | 13 | ||
| 10 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 14 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
| 15 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | ||
| 16 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | ||
| 17 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | ||
| 11 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 18 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
| 12 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 19 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
| 13 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 20 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
| 21 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | ||
| 14 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 22 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
| 15 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 23 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
| 16 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 2a1ffe396908..61fd96ca7bc7 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
| @@ -10,9 +10,6 @@ | |||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. | 11 | * option) any later version. |
| 12 | * | 12 | * |
| 13 | * Revision history | ||
| 14 | * 17th Oct 2005 Initial version. | ||
| 15 | * | ||
| 16 | * Generic AC97 support. | 13 | * Generic AC97 support. |
| 17 | */ | 14 | */ |
| 18 | 15 | ||
| @@ -24,6 +21,7 @@ | |||
| 24 | #include <sound/ac97_codec.h> | 21 | #include <sound/ac97_codec.h> |
| 25 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
| 26 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
| 24 | #include "ac97.h" | ||
| 27 | 25 | ||
| 28 | #define AC97_VERSION "0.6" | 26 | #define AC97_VERSION "0.6" |
| 29 | 27 | ||
| @@ -43,7 +41,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream) | |||
| 43 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 41 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
| 44 | SNDRV_PCM_RATE_48000) | 42 | SNDRV_PCM_RATE_48000) |
| 45 | 43 | ||
| 46 | struct snd_soc_codec_dai ac97_dai = { | 44 | struct snd_soc_dai ac97_dai = { |
| 47 | .name = "AC97 HiFi", | 45 | .name = "AC97 HiFi", |
| 48 | .type = SND_SOC_DAI_AC97, | 46 | .type = SND_SOC_DAI_AC97, |
| 49 | .playback = { | 47 | .playback = { |
| @@ -146,9 +144,34 @@ static int ac97_soc_remove(struct platform_device *pdev) | |||
| 146 | return 0; | 144 | return 0; |
| 147 | } | 145 | } |
| 148 | 146 | ||
| 147 | #ifdef CONFIG_PM | ||
| 148 | static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg) | ||
| 149 | { | ||
| 150 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 151 | |||
| 152 | snd_ac97_suspend(socdev->codec->ac97); | ||
| 153 | |||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static int ac97_soc_resume(struct platform_device *pdev) | ||
| 158 | { | ||
| 159 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 160 | |||
| 161 | snd_ac97_resume(socdev->codec->ac97); | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | #else | ||
| 166 | #define ac97_soc_suspend NULL | ||
| 167 | #define ac97_soc_resume NULL | ||
| 168 | #endif | ||
| 169 | |||
| 149 | struct snd_soc_codec_device soc_codec_dev_ac97 = { | 170 | struct snd_soc_codec_device soc_codec_dev_ac97 = { |
| 150 | .probe = ac97_soc_probe, | 171 | .probe = ac97_soc_probe, |
| 151 | .remove = ac97_soc_remove, | 172 | .remove = ac97_soc_remove, |
| 173 | .suspend = ac97_soc_suspend, | ||
| 174 | .resume = ac97_soc_resume, | ||
| 152 | }; | 175 | }; |
| 153 | EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); | 176 | EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); |
| 154 | 177 | ||
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h index 2bf6d69fd069..281aa42e2bbb 100644 --- a/sound/soc/codecs/ac97.h +++ b/sound/soc/codecs/ac97.h | |||
| @@ -14,6 +14,6 @@ | |||
| 14 | #define __LINUX_SND_SOC_AC97_H | 14 | #define __LINUX_SND_SOC_AC97_H |
| 15 | 15 | ||
| 16 | extern struct snd_soc_codec_device soc_codec_dev_ac97; | 16 | extern struct snd_soc_codec_device soc_codec_dev_ac97; |
| 17 | extern struct snd_soc_codec_dai ac97_dai; | 17 | extern struct snd_soc_dai ac97_dai; |
| 18 | 18 | ||
| 19 | #endif | 19 | #endif |
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c new file mode 100644 index 000000000000..b26003c4f3e8 --- /dev/null +++ b/sound/soc/codecs/ak4535.c | |||
| @@ -0,0 +1,696 @@ | |||
| 1 | /* | ||
| 2 | * ak4535.c -- AK4535 ALSA Soc Audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2005 Openedhand Ltd. | ||
| 5 | * | ||
| 6 | * Author: Richard Purdie <richard@openedhand.com> | ||
| 7 | * | ||
| 8 | * Based on wm8753.c by Liam Girdwood | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/moduleparam.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/pm.h> | ||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <sound/core.h> | ||
| 23 | #include <sound/pcm.h> | ||
| 24 | #include <sound/pcm_params.h> | ||
| 25 | #include <sound/soc.h> | ||
| 26 | #include <sound/soc-dapm.h> | ||
| 27 | #include <sound/initval.h> | ||
| 28 | |||
| 29 | #include "ak4535.h" | ||
| 30 | |||
| 31 | #define AUDIO_NAME "ak4535" | ||
| 32 | #define AK4535_VERSION "0.3" | ||
| 33 | |||
| 34 | struct snd_soc_codec_device soc_codec_dev_ak4535; | ||
| 35 | |||
| 36 | /* codec private data */ | ||
| 37 | struct ak4535_priv { | ||
| 38 | unsigned int sysclk; | ||
| 39 | }; | ||
| 40 | |||
| 41 | /* | ||
| 42 | * ak4535 register cache | ||
| 43 | */ | ||
| 44 | static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { | ||
| 45 | 0x0000, 0x0080, 0x0000, 0x0003, | ||
| 46 | 0x0002, 0x0000, 0x0011, 0x0001, | ||
| 47 | 0x0000, 0x0040, 0x0036, 0x0010, | ||
| 48 | 0x0000, 0x0000, 0x0057, 0x0000, | ||
| 49 | }; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * read ak4535 register cache | ||
| 53 | */ | ||
| 54 | static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec, | ||
| 55 | unsigned int reg) | ||
| 56 | { | ||
| 57 | u16 *cache = codec->reg_cache; | ||
| 58 | if (reg >= AK4535_CACHEREGNUM) | ||
| 59 | return -1; | ||
| 60 | return cache[reg]; | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline unsigned int ak4535_read(struct snd_soc_codec *codec, | ||
| 64 | unsigned int reg) | ||
| 65 | { | ||
| 66 | u8 data; | ||
| 67 | data = reg; | ||
| 68 | |||
| 69 | if (codec->hw_write(codec->control_data, &data, 1) != 1) | ||
| 70 | return -EIO; | ||
| 71 | |||
| 72 | if (codec->hw_read(codec->control_data, &data, 1) != 1) | ||
| 73 | return -EIO; | ||
| 74 | |||
| 75 | return data; | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* | ||
| 79 | * write ak4535 register cache | ||
| 80 | */ | ||
| 81 | static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec, | ||
| 82 | u16 reg, unsigned int value) | ||
| 83 | { | ||
| 84 | u16 *cache = codec->reg_cache; | ||
| 85 | if (reg >= AK4535_CACHEREGNUM) | ||
| 86 | return; | ||
| 87 | cache[reg] = value; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | * write to the AK4535 register space | ||
| 92 | */ | ||
| 93 | static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg, | ||
| 94 | unsigned int value) | ||
| 95 | { | ||
| 96 | u8 data[2]; | ||
| 97 | |||
| 98 | /* data is | ||
| 99 | * D15..D8 AK4535 register offset | ||
| 100 | * D7...D0 register data | ||
| 101 | */ | ||
| 102 | data[0] = reg & 0xff; | ||
| 103 | data[1] = value & 0xff; | ||
| 104 | |||
| 105 | ak4535_write_reg_cache(codec, reg, value); | ||
| 106 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
| 107 | return 0; | ||
| 108 | else | ||
| 109 | return -EIO; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int ak4535_sync(struct snd_soc_codec *codec) | ||
| 113 | { | ||
| 114 | u16 *cache = codec->reg_cache; | ||
| 115 | int i, r = 0; | ||
| 116 | |||
| 117 | for (i = 0; i < AK4535_CACHEREGNUM; i++) | ||
| 118 | r |= ak4535_write(codec, i, cache[i]); | ||
| 119 | |||
| 120 | return r; | ||
| 121 | }; | ||
| 122 | |||
| 123 | static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; | ||
| 124 | static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"}; | ||
| 125 | static const char *ak4535_hp_out[] = {"Stereo", "Mono"}; | ||
| 126 | static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"}; | ||
| 127 | static const char *ak4535_mic_select[] = {"Internal", "External"}; | ||
| 128 | |||
| 129 | static const struct soc_enum ak4535_enum[] = { | ||
| 130 | SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain), | ||
| 131 | SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out), | ||
| 132 | SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out), | ||
| 133 | SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp), | ||
| 134 | SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select), | ||
| 135 | }; | ||
| 136 | |||
| 137 | static const struct snd_kcontrol_new ak4535_snd_controls[] = { | ||
| 138 | SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0), | ||
| 139 | SOC_ENUM("Mono 1 Output", ak4535_enum[1]), | ||
| 140 | SOC_ENUM("Mono 1 Gain", ak4535_enum[0]), | ||
| 141 | SOC_ENUM("Headphone Output", ak4535_enum[2]), | ||
| 142 | SOC_ENUM("Playback Deemphasis", ak4535_enum[3]), | ||
| 143 | SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0), | ||
| 144 | SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0), | ||
| 145 | SOC_ENUM("Mic Select", ak4535_enum[4]), | ||
| 146 | SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0), | ||
| 147 | SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0), | ||
| 148 | SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0), | ||
| 149 | SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0), | ||
| 150 | SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0), | ||
| 151 | SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0), | ||
| 152 | SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0), | ||
| 153 | SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1), | ||
| 154 | SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1), | ||
| 155 | SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0), | ||
| 156 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), | ||
| 157 | }; | ||
| 158 | |||
| 159 | /* add non dapm controls */ | ||
| 160 | static int ak4535_add_controls(struct snd_soc_codec *codec) | ||
| 161 | { | ||
| 162 | int err, i; | ||
| 163 | |||
| 164 | for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { | ||
| 165 | err = snd_ctl_add(codec->card, | ||
| 166 | snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); | ||
| 167 | if (err < 0) | ||
| 168 | return err; | ||
| 169 | } | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | /* Mono 1 Mixer */ | ||
| 175 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { | ||
| 176 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), | ||
| 177 | SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0), | ||
| 178 | }; | ||
| 179 | |||
| 180 | /* Stereo Mixer */ | ||
| 181 | static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = { | ||
| 182 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0), | ||
| 183 | SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0), | ||
| 184 | SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0), | ||
| 185 | }; | ||
| 186 | |||
| 187 | /* Input Mixer */ | ||
| 188 | static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = { | ||
| 189 | SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0), | ||
| 190 | SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0), | ||
| 191 | }; | ||
| 192 | |||
| 193 | /* Input mux */ | ||
| 194 | static const struct snd_kcontrol_new ak4535_input_mux_control = | ||
| 195 | SOC_DAPM_ENUM("Input Select", ak4535_enum[4]); | ||
| 196 | |||
| 197 | /* HP L switch */ | ||
| 198 | static const struct snd_kcontrol_new ak4535_hpl_control = | ||
| 199 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1); | ||
| 200 | |||
| 201 | /* HP R switch */ | ||
| 202 | static const struct snd_kcontrol_new ak4535_hpr_control = | ||
| 203 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1); | ||
| 204 | |||
| 205 | /* mono 2 switch */ | ||
| 206 | static const struct snd_kcontrol_new ak4535_mono2_control = | ||
| 207 | SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0); | ||
| 208 | |||
| 209 | /* Line out switch */ | ||
| 210 | static const struct snd_kcontrol_new ak4535_line_control = | ||
| 211 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0); | ||
| 212 | |||
| 213 | /* ak4535 dapm widgets */ | ||
| 214 | static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = { | ||
| 215 | SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0, | ||
| 216 | &ak4535_stereo_mixer_controls[0], | ||
| 217 | ARRAY_SIZE(ak4535_stereo_mixer_controls)), | ||
| 218 | SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, | ||
| 219 | &ak4535_mono1_mixer_controls[0], | ||
| 220 | ARRAY_SIZE(ak4535_mono1_mixer_controls)), | ||
| 221 | SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, | ||
| 222 | &ak4535_input_mixer_controls[0], | ||
| 223 | ARRAY_SIZE(ak4535_input_mixer_controls)), | ||
| 224 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
| 225 | &ak4535_input_mux_control), | ||
| 226 | SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0), | ||
| 227 | SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, | ||
| 228 | &ak4535_mono2_control), | ||
| 229 | /* speaker powersave bit */ | ||
| 230 | SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0), | ||
| 231 | SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0, | ||
| 232 | &ak4535_line_control), | ||
| 233 | SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0, | ||
| 234 | &ak4535_hpl_control), | ||
| 235 | SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0, | ||
| 236 | &ak4535_hpr_control), | ||
| 237 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
| 238 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
| 239 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
| 240 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
| 241 | SND_SOC_DAPM_OUTPUT("SPP"), | ||
| 242 | SND_SOC_DAPM_OUTPUT("SPN"), | ||
| 243 | SND_SOC_DAPM_OUTPUT("MOUT1"), | ||
| 244 | SND_SOC_DAPM_OUTPUT("MOUT2"), | ||
| 245 | SND_SOC_DAPM_OUTPUT("MICOUT"), | ||
| 246 | SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0), | ||
| 247 | SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0), | ||
| 248 | SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0), | ||
| 249 | SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0), | ||
| 250 | SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0), | ||
| 251 | SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0), | ||
| 252 | SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0), | ||
| 253 | SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0), | ||
| 254 | |||
| 255 | SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0), | ||
| 256 | SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0), | ||
| 257 | SND_SOC_DAPM_INPUT("MICIN"), | ||
| 258 | SND_SOC_DAPM_INPUT("MICEXT"), | ||
| 259 | SND_SOC_DAPM_INPUT("AUX"), | ||
| 260 | SND_SOC_DAPM_INPUT("MIN"), | ||
| 261 | SND_SOC_DAPM_INPUT("AIN"), | ||
| 262 | }; | ||
| 263 | |||
| 264 | static const struct snd_soc_dapm_route audio_map[] = { | ||
| 265 | /*stereo mixer */ | ||
| 266 | {"Stereo Mixer", "Playback Switch", "DAC"}, | ||
| 267 | {"Stereo Mixer", "Mic Sidetone Switch", "Mic"}, | ||
| 268 | {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, | ||
| 269 | |||
| 270 | /* mono1 mixer */ | ||
| 271 | {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"}, | ||
| 272 | {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, | ||
| 273 | |||
| 274 | /* Mic */ | ||
| 275 | {"Mic", NULL, "AIN"}, | ||
| 276 | {"Input Mux", "Internal", "Mic Int Bias"}, | ||
| 277 | {"Input Mux", "External", "Mic Ext Bias"}, | ||
| 278 | {"Mic Int Bias", NULL, "MICIN"}, | ||
| 279 | {"Mic Ext Bias", NULL, "MICEXT"}, | ||
| 280 | {"MICOUT", NULL, "Input Mux"}, | ||
| 281 | |||
| 282 | /* line out */ | ||
| 283 | {"LOUT", NULL, "Line Out Enable"}, | ||
| 284 | {"ROUT", NULL, "Line Out Enable"}, | ||
| 285 | {"Line Out Enable", "Switch", "Line Out"}, | ||
| 286 | {"Line Out", NULL, "Stereo Mixer"}, | ||
| 287 | |||
| 288 | /* mono1 out */ | ||
| 289 | {"MOUT1", NULL, "Mono Out"}, | ||
| 290 | {"Mono Out", NULL, "Mono1 Mixer"}, | ||
| 291 | |||
| 292 | /* left HP */ | ||
| 293 | {"HPL", NULL, "Left HP Enable"}, | ||
| 294 | {"Left HP Enable", "Switch", "HP L Amp"}, | ||
| 295 | {"HP L Amp", NULL, "Stereo Mixer"}, | ||
| 296 | |||
| 297 | /* right HP */ | ||
| 298 | {"HPR", NULL, "Right HP Enable"}, | ||
| 299 | {"Right HP Enable", "Switch", "HP R Amp"}, | ||
| 300 | {"HP R Amp", NULL, "Stereo Mixer"}, | ||
| 301 | |||
| 302 | /* speaker */ | ||
| 303 | {"SPP", NULL, "Speaker Enable"}, | ||
| 304 | {"SPN", NULL, "Speaker Enable"}, | ||
| 305 | {"Speaker Enable", "Switch", "Spk Amp"}, | ||
| 306 | {"Spk Amp", NULL, "MIN"}, | ||
| 307 | |||
| 308 | /* mono 2 */ | ||
| 309 | {"MOUT2", NULL, "Mono 2 Enable"}, | ||
| 310 | {"Mono 2 Enable", "Switch", "Stereo Mixer"}, | ||
| 311 | |||
| 312 | /* Aux In */ | ||
| 313 | {"Aux In", NULL, "AUX"}, | ||
| 314 | |||
| 315 | /* ADC */ | ||
| 316 | {"ADC", NULL, "Input Mixer"}, | ||
| 317 | {"Input Mixer", "Mic Capture Switch", "Mic"}, | ||
| 318 | {"Input Mixer", "Aux Capture Switch", "Aux In"}, | ||
| 319 | }; | ||
| 320 | |||
| 321 | static int ak4535_add_widgets(struct snd_soc_codec *codec) | ||
| 322 | { | ||
| 323 | snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets, | ||
| 324 | ARRAY_SIZE(ak4535_dapm_widgets)); | ||
| 325 | |||
| 326 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
| 327 | |||
| 328 | snd_soc_dapm_new_widgets(codec); | ||
| 329 | return 0; | ||
| 330 | } | ||
| 331 | |||
| 332 | static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
| 333 | int clk_id, unsigned int freq, int dir) | ||
| 334 | { | ||
| 335 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 336 | struct ak4535_priv *ak4535 = codec->private_data; | ||
| 337 | |||
| 338 | ak4535->sysclk = freq; | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static int ak4535_hw_params(struct snd_pcm_substream *substream, | ||
| 343 | struct snd_pcm_hw_params *params) | ||
| 344 | { | ||
| 345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 346 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 347 | struct snd_soc_codec *codec = socdev->codec; | ||
| 348 | struct ak4535_priv *ak4535 = codec->private_data; | ||
| 349 | u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); | ||
| 350 | int rate = params_rate(params), fs = 256; | ||
| 351 | |||
| 352 | if (rate) | ||
| 353 | fs = ak4535->sysclk / rate; | ||
| 354 | |||
| 355 | /* set fs */ | ||
| 356 | switch (fs) { | ||
| 357 | case 1024: | ||
| 358 | mode2 |= (0x2 << 5); | ||
| 359 | break; | ||
| 360 | case 512: | ||
| 361 | mode2 |= (0x1 << 5); | ||
| 362 | break; | ||
| 363 | case 256: | ||
| 364 | break; | ||
| 365 | } | ||
| 366 | |||
| 367 | /* set rate */ | ||
| 368 | ak4535_write(codec, AK4535_MODE2, mode2); | ||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | |||
| 372 | static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
| 373 | unsigned int fmt) | ||
| 374 | { | ||
| 375 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 376 | u8 mode1 = 0; | ||
| 377 | |||
| 378 | /* interface format */ | ||
| 379 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 380 | case SND_SOC_DAIFMT_I2S: | ||
| 381 | mode1 = 0x0002; | ||
| 382 | break; | ||
| 383 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 384 | mode1 = 0x0001; | ||
| 385 | break; | ||
| 386 | default: | ||
| 387 | return -EINVAL; | ||
| 388 | } | ||
| 389 | |||
| 390 | /* use 32 fs for BCLK to save power */ | ||
| 391 | mode1 |= 0x4; | ||
| 392 | |||
| 393 | ak4535_write(codec, AK4535_MODE1, mode1); | ||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | static int ak4535_mute(struct snd_soc_dai *dai, int mute) | ||
| 398 | { | ||
| 399 | struct snd_soc_codec *codec = dai->codec; | ||
| 400 | u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf; | ||
| 401 | if (!mute) | ||
| 402 | ak4535_write(codec, AK4535_DAC, mute_reg); | ||
| 403 | else | ||
| 404 | ak4535_write(codec, AK4535_DAC, mute_reg | 0x20); | ||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | |||
| 408 | static int ak4535_set_bias_level(struct snd_soc_codec *codec, | ||
| 409 | enum snd_soc_bias_level level) | ||
| 410 | { | ||
| 411 | u16 i; | ||
| 412 | |||
| 413 | switch (level) { | ||
| 414 | case SND_SOC_BIAS_ON: | ||
| 415 | ak4535_mute(codec->dai, 0); | ||
| 416 | break; | ||
| 417 | case SND_SOC_BIAS_PREPARE: | ||
| 418 | ak4535_mute(codec->dai, 1); | ||
| 419 | break; | ||
| 420 | case SND_SOC_BIAS_STANDBY: | ||
| 421 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | ||
| 422 | ak4535_write(codec, AK4535_PM1, i | 0x80); | ||
| 423 | i = ak4535_read_reg_cache(codec, AK4535_PM2); | ||
| 424 | ak4535_write(codec, AK4535_PM2, i & (~0x80)); | ||
| 425 | break; | ||
| 426 | case SND_SOC_BIAS_OFF: | ||
| 427 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | ||
| 428 | ak4535_write(codec, AK4535_PM1, i & (~0x80)); | ||
| 429 | break; | ||
| 430 | } | ||
| 431 | codec->bias_level = level; | ||
| 432 | return 0; | ||
| 433 | } | ||
| 434 | |||
| 435 | #define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
| 436 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
| 437 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
| 438 | |||
| 439 | struct snd_soc_dai ak4535_dai = { | ||
| 440 | .name = "AK4535", | ||
| 441 | .playback = { | ||
| 442 | .stream_name = "Playback", | ||
| 443 | .channels_min = 1, | ||
| 444 | .channels_max = 2, | ||
| 445 | .rates = AK4535_RATES, | ||
| 446 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
| 447 | .capture = { | ||
| 448 | .stream_name = "Capture", | ||
| 449 | .channels_min = 1, | ||
| 450 | .channels_max = 2, | ||
| 451 | .rates = AK4535_RATES, | ||
| 452 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
| 453 | .ops = { | ||
| 454 | .hw_params = ak4535_hw_params, | ||
| 455 | }, | ||
| 456 | .dai_ops = { | ||
| 457 | .set_fmt = ak4535_set_dai_fmt, | ||
| 458 | .digital_mute = ak4535_mute, | ||
| 459 | .set_sysclk = ak4535_set_dai_sysclk, | ||
| 460 | }, | ||
| 461 | }; | ||
| 462 | EXPORT_SYMBOL_GPL(ak4535_dai); | ||
| 463 | |||
| 464 | static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 465 | { | ||
| 466 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 467 | struct snd_soc_codec *codec = socdev->codec; | ||
| 468 | |||
| 469 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 470 | return 0; | ||
| 471 | } | ||
| 472 | |||
| 473 | static int ak4535_resume(struct platform_device *pdev) | ||
| 474 | { | ||
| 475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 476 | struct snd_soc_codec *codec = socdev->codec; | ||
| 477 | ak4535_sync(codec); | ||
| 478 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 479 | ak4535_set_bias_level(codec, codec->suspend_bias_level); | ||
| 480 | return 0; | ||
| 481 | } | ||
| 482 | |||
| 483 | /* | ||
| 484 | * initialise the AK4535 driver | ||
| 485 | * register the mixer and dsp interfaces with the kernel | ||
| 486 | */ | ||
| 487 | static int ak4535_init(struct snd_soc_device *socdev) | ||
| 488 | { | ||
| 489 | struct snd_soc_codec *codec = socdev->codec; | ||
| 490 | int ret = 0; | ||
| 491 | |||
| 492 | codec->name = "AK4535"; | ||
| 493 | codec->owner = THIS_MODULE; | ||
| 494 | codec->read = ak4535_read_reg_cache; | ||
| 495 | codec->write = ak4535_write; | ||
| 496 | codec->set_bias_level = ak4535_set_bias_level; | ||
| 497 | codec->dai = &ak4535_dai; | ||
| 498 | codec->num_dai = 1; | ||
| 499 | codec->reg_cache_size = ARRAY_SIZE(ak4535_reg); | ||
| 500 | codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL); | ||
| 501 | |||
| 502 | if (codec->reg_cache == NULL) | ||
| 503 | return -ENOMEM; | ||
| 504 | |||
| 505 | /* register pcms */ | ||
| 506 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
| 507 | if (ret < 0) { | ||
| 508 | printk(KERN_ERR "ak4535: failed to create pcms\n"); | ||
| 509 | goto pcm_err; | ||
| 510 | } | ||
| 511 | |||
| 512 | /* power on device */ | ||
| 513 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 514 | |||
| 515 | ak4535_add_controls(codec); | ||
| 516 | ak4535_add_widgets(codec); | ||
| 517 | ret = snd_soc_register_card(socdev); | ||
| 518 | if (ret < 0) { | ||
| 519 | printk(KERN_ERR "ak4535: failed to register card\n"); | ||
| 520 | goto card_err; | ||
| 521 | } | ||
| 522 | |||
| 523 | return ret; | ||
| 524 | |||
| 525 | card_err: | ||
| 526 | snd_soc_free_pcms(socdev); | ||
| 527 | snd_soc_dapm_free(socdev); | ||
| 528 | pcm_err: | ||
| 529 | kfree(codec->reg_cache); | ||
| 530 | |||
| 531 | return ret; | ||
| 532 | } | ||
| 533 | |||
| 534 | static struct snd_soc_device *ak4535_socdev; | ||
| 535 | |||
| 536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 537 | |||
| 538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ | ||
| 539 | |||
| 540 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
| 541 | |||
| 542 | /* Magic definition of all other variables and things */ | ||
| 543 | I2C_CLIENT_INSMOD; | ||
| 544 | |||
| 545 | static struct i2c_driver ak4535_i2c_driver; | ||
| 546 | static struct i2c_client client_template; | ||
| 547 | |||
| 548 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
| 549 | around */ | ||
| 550 | static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
| 551 | { | ||
| 552 | struct snd_soc_device *socdev = ak4535_socdev; | ||
| 553 | struct ak4535_setup_data *setup = socdev->codec_data; | ||
| 554 | struct snd_soc_codec *codec = socdev->codec; | ||
| 555 | struct i2c_client *i2c; | ||
| 556 | int ret; | ||
| 557 | |||
| 558 | if (addr != setup->i2c_address) | ||
| 559 | return -ENODEV; | ||
| 560 | |||
| 561 | client_template.adapter = adap; | ||
| 562 | client_template.addr = addr; | ||
| 563 | |||
| 564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
| 565 | if (i2c == NULL) { | ||
| 566 | kfree(codec); | ||
| 567 | return -ENOMEM; | ||
| 568 | } | ||
| 569 | i2c_set_clientdata(i2c, codec); | ||
| 570 | codec->control_data = i2c; | ||
| 571 | |||
| 572 | ret = i2c_attach_client(i2c); | ||
| 573 | if (ret < 0) { | ||
| 574 | printk(KERN_ERR "failed to attach codec at addr %x\n", addr); | ||
| 575 | goto err; | ||
| 576 | } | ||
| 577 | |||
| 578 | ret = ak4535_init(socdev); | ||
| 579 | if (ret < 0) { | ||
| 580 | printk(KERN_ERR "failed to initialise AK4535\n"); | ||
| 581 | goto err; | ||
| 582 | } | ||
| 583 | return ret; | ||
| 584 | |||
| 585 | err: | ||
| 586 | kfree(codec); | ||
| 587 | kfree(i2c); | ||
| 588 | return ret; | ||
| 589 | } | ||
| 590 | |||
| 591 | static int ak4535_i2c_detach(struct i2c_client *client) | ||
| 592 | { | ||
| 593 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
| 594 | i2c_detach_client(client); | ||
| 595 | kfree(codec->reg_cache); | ||
| 596 | kfree(client); | ||
| 597 | return 0; | ||
| 598 | } | ||
| 599 | |||
| 600 | static int ak4535_i2c_attach(struct i2c_adapter *adap) | ||
| 601 | { | ||
| 602 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); | ||
| 603 | } | ||
| 604 | |||
| 605 | /* corgi i2c codec control layer */ | ||
| 606 | static struct i2c_driver ak4535_i2c_driver = { | ||
| 607 | .driver = { | ||
| 608 | .name = "AK4535 I2C Codec", | ||
| 609 | .owner = THIS_MODULE, | ||
| 610 | }, | ||
| 611 | .id = I2C_DRIVERID_AK4535, | ||
| 612 | .attach_adapter = ak4535_i2c_attach, | ||
| 613 | .detach_client = ak4535_i2c_detach, | ||
| 614 | .command = NULL, | ||
| 615 | }; | ||
| 616 | |||
| 617 | static struct i2c_client client_template = { | ||
| 618 | .name = "AK4535", | ||
| 619 | .driver = &ak4535_i2c_driver, | ||
| 620 | }; | ||
| 621 | #endif | ||
| 622 | |||
| 623 | static int ak4535_probe(struct platform_device *pdev) | ||
| 624 | { | ||
| 625 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 626 | struct ak4535_setup_data *setup; | ||
| 627 | struct snd_soc_codec *codec; | ||
| 628 | struct ak4535_priv *ak4535; | ||
| 629 | int ret = 0; | ||
| 630 | |||
| 631 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); | ||
| 632 | |||
| 633 | setup = socdev->codec_data; | ||
| 634 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
| 635 | if (codec == NULL) | ||
| 636 | return -ENOMEM; | ||
| 637 | |||
| 638 | ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL); | ||
| 639 | if (ak4535 == NULL) { | ||
| 640 | kfree(codec); | ||
| 641 | return -ENOMEM; | ||
| 642 | } | ||
| 643 | |||
| 644 | codec->private_data = ak4535; | ||
| 645 | socdev->codec = codec; | ||
| 646 | mutex_init(&codec->mutex); | ||
| 647 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
| 648 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
| 649 | |||
| 650 | ak4535_socdev = socdev; | ||
| 651 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 652 | if (setup->i2c_address) { | ||
| 653 | normal_i2c[0] = setup->i2c_address; | ||
| 654 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
| 655 | codec->hw_read = (hw_read_t)i2c_master_recv; | ||
| 656 | ret = i2c_add_driver(&ak4535_i2c_driver); | ||
| 657 | if (ret != 0) | ||
| 658 | printk(KERN_ERR "can't add i2c driver"); | ||
| 659 | } | ||
| 660 | #else | ||
| 661 | /* Add other interfaces here */ | ||
| 662 | #endif | ||
| 663 | return ret; | ||
| 664 | } | ||
| 665 | |||
| 666 | /* power down chip */ | ||
| 667 | static int ak4535_remove(struct platform_device *pdev) | ||
| 668 | { | ||
| 669 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 670 | struct snd_soc_codec *codec = socdev->codec; | ||
| 671 | |||
| 672 | if (codec->control_data) | ||
| 673 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 674 | |||
| 675 | snd_soc_free_pcms(socdev); | ||
| 676 | snd_soc_dapm_free(socdev); | ||
| 677 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 678 | i2c_del_driver(&ak4535_i2c_driver); | ||
| 679 | #endif | ||
| 680 | kfree(codec->private_data); | ||
| 681 | kfree(codec); | ||
| 682 | |||
| 683 | return 0; | ||
| 684 | } | ||
| 685 | |||
| 686 | struct snd_soc_codec_device soc_codec_dev_ak4535 = { | ||
| 687 | .probe = ak4535_probe, | ||
| 688 | .remove = ak4535_remove, | ||
| 689 | .suspend = ak4535_suspend, | ||
| 690 | .resume = ak4535_resume, | ||
| 691 | }; | ||
| 692 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); | ||
| 693 | |||
| 694 | MODULE_DESCRIPTION("Soc AK4535 driver"); | ||
| 695 | MODULE_AUTHOR("Richard Purdie"); | ||
| 696 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h new file mode 100644 index 000000000000..e9fe30e2c056 --- /dev/null +++ b/sound/soc/codecs/ak4535.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * ak4535.h -- AK4535 Soc Audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2005 Openedhand Ltd. | ||
| 5 | * | ||
| 6 | * Author: Richard Purdie <richard@openedhand.com> | ||
| 7 | * | ||
| 8 | * Based on wm8753.h | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef _AK4535_H | ||
| 16 | #define _AK4535_H | ||
| 17 | |||
| 18 | /* AK4535 register space */ | ||
| 19 | |||
| 20 | #define AK4535_PM1 0x0 | ||
| 21 | #define AK4535_PM2 0x1 | ||
| 22 | #define AK4535_SIG1 0x2 | ||
| 23 | #define AK4535_SIG2 0x3 | ||
| 24 | #define AK4535_MODE1 0x4 | ||
| 25 | #define AK4535_MODE2 0x5 | ||
| 26 | #define AK4535_DAC 0x6 | ||
| 27 | #define AK4535_MIC 0x7 | ||
| 28 | #define AK4535_TIMER 0x8 | ||
| 29 | #define AK4535_ALC1 0x9 | ||
| 30 | #define AK4535_ALC2 0xa | ||
| 31 | #define AK4535_PGA 0xb | ||
| 32 | #define AK4535_LATT 0xc | ||
| 33 | #define AK4535_RATT 0xd | ||
| 34 | #define AK4535_VOL 0xe | ||
| 35 | #define AK4535_STATUS 0xf | ||
| 36 | |||
| 37 | #define AK4535_CACHEREGNUM 0x10 | ||
| 38 | |||
| 39 | struct ak4535_setup_data { | ||
| 40 | unsigned short i2c_address; | ||
| 41 | }; | ||
| 42 | |||
| 43 | extern struct snd_soc_dai ak4535_dai; | ||
| 44 | extern struct snd_soc_codec_device soc_codec_dev_ak4535; | ||
| 45 | |||
| 46 | #endif | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index e73fcfd9f5cd..9deb8c74fdfd 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
| @@ -201,7 +201,7 @@ static struct { | |||
| 201 | * driver what the input settings can be. This would need to be implemented | 201 | * driver what the input settings can be. This would need to be implemented |
| 202 | * for stand-alone mode to work. | 202 | * for stand-alone mode to work. |
| 203 | */ | 203 | */ |
| 204 | static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 204 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
| 205 | int clk_id, unsigned int freq, int dir) | 205 | int clk_id, unsigned int freq, int dir) |
| 206 | { | 206 | { |
| 207 | struct snd_soc_codec *codec = codec_dai->codec; | 207 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -251,7 +251,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
| 251 | * data for playback only, but ASoC currently does not support different | 251 | * data for playback only, but ASoC currently does not support different |
| 252 | * formats for playback vs. record. | 252 | * formats for playback vs. record. |
| 253 | */ | 253 | */ |
| 254 | static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 254 | static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 255 | unsigned int format) | 255 | unsigned int format) |
| 256 | { | 256 | { |
| 257 | struct snd_soc_codec *codec = codec_dai->codec; | 257 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -471,7 +471,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
| 471 | * board does not have the MUTEA or MUTEB pins connected to such circuitry, | 471 | * board does not have the MUTEA or MUTEB pins connected to such circuitry, |
| 472 | * then this function will do nothing. | 472 | * then this function will do nothing. |
| 473 | */ | 473 | */ |
| 474 | static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute) | 474 | static int cs4270_mute(struct snd_soc_dai *dai, int mute) |
| 475 | { | 475 | { |
| 476 | struct snd_soc_codec *codec = dai->codec; | 476 | struct snd_soc_codec *codec = dai->codec; |
| 477 | int reg6; | 477 | int reg6; |
| @@ -667,7 +667,7 @@ error: | |||
| 667 | 667 | ||
| 668 | #endif /* USE_I2C*/ | 668 | #endif /* USE_I2C*/ |
| 669 | 669 | ||
| 670 | struct snd_soc_codec_dai cs4270_dai = { | 670 | struct snd_soc_dai cs4270_dai = { |
| 671 | .name = "CS4270", | 671 | .name = "CS4270", |
| 672 | .playback = { | 672 | .playback = { |
| 673 | .stream_name = "Playback", | 673 | .stream_name = "Playback", |
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h index 0ced49b7804d..adc6cd9667d4 100644 --- a/sound/soc/codecs/cs4270.h +++ b/sound/soc/codecs/cs4270.h | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | * The ASoC codec DAI structure for the CS4270. Assign this structure to | 16 | * The ASoC codec DAI structure for the CS4270. Assign this structure to |
| 17 | * the .codec_dai field of your machine driver's snd_soc_dai_link structure. | 17 | * the .codec_dai field of your machine driver's snd_soc_dai_link structure. |
| 18 | */ | 18 | */ |
| 19 | extern struct snd_soc_codec_dai cs4270_dai; | 19 | extern struct snd_soc_dai cs4270_dai; |
| 20 | 20 | ||
| 21 | /* | 21 | /* |
| 22 | * The ASoC codec device structure for the CS4270. Assign this structure | 22 | * The ASoC codec device structure for the CS4270. Assign this structure |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 09b1661b8a3a..b1dce5f459db 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | * --------------------------------------- | 29 | * --------------------------------------- |
| 30 | * | 30 | * |
| 31 | * Hence the machine layer should disable unsupported inputs/outputs by | 31 | * Hence the machine layer should disable unsupported inputs/outputs by |
| 32 | * snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0), etc. | 32 | * snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc. |
| 33 | */ | 33 | */ |
| 34 | 34 | ||
| 35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
| @@ -49,7 +49,7 @@ | |||
| 49 | #include "tlv320aic3x.h" | 49 | #include "tlv320aic3x.h" |
| 50 | 50 | ||
| 51 | #define AUDIO_NAME "aic3x" | 51 | #define AUDIO_NAME "aic3x" |
| 52 | #define AIC3X_VERSION "0.1" | 52 | #define AIC3X_VERSION "0.2" |
| 53 | 53 | ||
| 54 | /* codec private data */ | 54 | /* codec private data */ |
| 55 | struct aic3x_priv { | 55 | struct aic3x_priv { |
| @@ -138,6 +138,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, | |||
| 138 | return -EIO; | 138 | return -EIO; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | /* | ||
| 142 | * read from the aic3x register space | ||
| 143 | */ | ||
| 144 | static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, | ||
| 145 | u8 *value) | ||
| 146 | { | ||
| 147 | *value = reg & 0xff; | ||
| 148 | if (codec->hw_read(codec->control_data, value, 1) != 1) | ||
| 149 | return -EIO; | ||
| 150 | |||
| 151 | aic3x_write_reg_cache(codec, reg, *value); | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 141 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ | 155 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ |
| 142 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 156 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| 143 | .info = snd_soc_info_volsw, \ | 157 | .info = snd_soc_info_volsw, \ |
| @@ -192,7 +206,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
| 192 | } | 206 | } |
| 193 | 207 | ||
| 194 | if (found) | 208 | if (found) |
| 195 | snd_soc_dapm_sync_endpoints(widget->codec); | 209 | snd_soc_dapm_sync(widget->codec); |
| 196 | } | 210 | } |
| 197 | 211 | ||
| 198 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 212 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); |
| @@ -209,6 +223,8 @@ static const char *aic3x_right_hpcom_mux[] = | |||
| 209 | { "differential of HPROUT", "constant VCM", "single-ended", | 223 | { "differential of HPROUT", "constant VCM", "single-ended", |
| 210 | "differential of HPLCOM", "external feedback" }; | 224 | "differential of HPLCOM", "external feedback" }; |
| 211 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | 225 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; |
| 226 | static const char *aic3x_adc_hpf[] = | ||
| 227 | { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; | ||
| 212 | 228 | ||
| 213 | #define LDAC_ENUM 0 | 229 | #define LDAC_ENUM 0 |
| 214 | #define RDAC_ENUM 1 | 230 | #define RDAC_ENUM 1 |
| @@ -218,6 +234,7 @@ static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | |||
| 218 | #define LINE1R_ENUM 5 | 234 | #define LINE1R_ENUM 5 |
| 219 | #define LINE2L_ENUM 6 | 235 | #define LINE2L_ENUM 6 |
| 220 | #define LINE2R_ENUM 7 | 236 | #define LINE2R_ENUM 7 |
| 237 | #define ADC_HPF_ENUM 8 | ||
| 221 | 238 | ||
| 222 | static const struct soc_enum aic3x_enum[] = { | 239 | static const struct soc_enum aic3x_enum[] = { |
| 223 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), | 240 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), |
| @@ -228,6 +245,7 @@ static const struct soc_enum aic3x_enum[] = { | |||
| 228 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 245 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
| 229 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 246 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
| 230 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 247 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
| 248 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), | ||
| 231 | }; | 249 | }; |
| 232 | 250 | ||
| 233 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { | 251 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { |
| @@ -278,6 +296,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
| 278 | /* Input */ | 296 | /* Input */ |
| 279 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), | 297 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), |
| 280 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), | 298 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), |
| 299 | |||
| 300 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | ||
| 281 | }; | 301 | }; |
| 282 | 302 | ||
| 283 | /* add non dapm controls */ | 303 | /* add non dapm controls */ |
| @@ -441,11 +461,34 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
| 441 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, | 461 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, |
| 442 | &aic3x_right_line2_mux_controls), | 462 | &aic3x_right_line2_mux_controls), |
| 443 | 463 | ||
| 464 | /* | ||
| 465 | * Not a real mic bias widget but similar function. This is for dynamic | ||
| 466 | * control of GPIO1 digital mic modulator clock output function when | ||
| 467 | * using digital mic. | ||
| 468 | */ | ||
| 469 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk", | ||
| 470 | AIC3X_GPIO1_REG, 4, 0xf, | ||
| 471 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK, | ||
| 472 | AIC3X_GPIO1_FUNC_DISABLED), | ||
| 473 | |||
| 474 | /* | ||
| 475 | * Also similar function like mic bias. Selects digital mic with | ||
| 476 | * configurable oversampling rate instead of ADC converter. | ||
| 477 | */ | ||
| 478 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128", | ||
| 479 | AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0), | ||
| 480 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64", | ||
| 481 | AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0), | ||
| 482 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", | ||
| 483 | AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), | ||
| 484 | |||
| 444 | /* Mic Bias */ | 485 | /* Mic Bias */ |
| 445 | SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0), | 486 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", |
| 446 | SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0), | 487 | MICBIAS_CTRL, 6, 3, 1, 0), |
| 447 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0), | 488 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", |
| 448 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0), | 489 | MICBIAS_CTRL, 6, 3, 2, 0), |
| 490 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", | ||
| 491 | MICBIAS_CTRL, 6, 3, 3, 0), | ||
| 449 | 492 | ||
| 450 | /* Left PGA to Left Output bypass */ | 493 | /* Left PGA to Left Output bypass */ |
| 451 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | 494 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, |
| @@ -483,7 +526,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
| 483 | SND_SOC_DAPM_INPUT("LINE2R"), | 526 | SND_SOC_DAPM_INPUT("LINE2R"), |
| 484 | }; | 527 | }; |
| 485 | 528 | ||
| 486 | static const char *intercon[][3] = { | 529 | static const struct snd_soc_dapm_route intercon[] = { |
| 487 | /* Left Output */ | 530 | /* Left Output */ |
| 488 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | 531 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, |
| 489 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, | 532 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, |
| @@ -554,6 +597,7 @@ static const char *intercon[][3] = { | |||
| 554 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, | 597 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, |
| 555 | 598 | ||
| 556 | {"Left ADC", NULL, "Left PGA Mixer"}, | 599 | {"Left ADC", NULL, "Left PGA Mixer"}, |
| 600 | {"Left ADC", NULL, "GPIO1 dmic modclk"}, | ||
| 557 | 601 | ||
| 558 | /* Right Input */ | 602 | /* Right Input */ |
| 559 | {"Right Line1R Mux", "single-ended", "LINE1R"}, | 603 | {"Right Line1R Mux", "single-ended", "LINE1R"}, |
| @@ -567,6 +611,7 @@ static const char *intercon[][3] = { | |||
| 567 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, | 611 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, |
| 568 | 612 | ||
| 569 | {"Right ADC", NULL, "Right PGA Mixer"}, | 613 | {"Right ADC", NULL, "Right PGA Mixer"}, |
| 614 | {"Right ADC", NULL, "GPIO1 dmic modclk"}, | ||
| 570 | 615 | ||
| 571 | /* Left PGA Bypass */ | 616 | /* Left PGA Bypass */ |
| 572 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, | 617 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, |
| @@ -628,101 +673,27 @@ static const char *intercon[][3] = { | |||
| 628 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, | 673 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, |
| 629 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, | 674 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, |
| 630 | 675 | ||
| 631 | /* terminator */ | 676 | /* |
| 632 | {NULL, NULL, NULL}, | 677 | * Logical path between digital mic enable and GPIO1 modulator clock |
| 678 | * output function | ||
| 679 | */ | ||
| 680 | {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, | ||
| 681 | {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, | ||
| 682 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, | ||
| 633 | }; | 683 | }; |
| 634 | 684 | ||
| 635 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 685 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
| 636 | { | 686 | { |
| 637 | int i; | 687 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
| 638 | 688 | ARRAY_SIZE(aic3x_dapm_widgets)); | |
| 639 | for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) | ||
| 640 | snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); | ||
| 641 | 689 | ||
| 642 | /* set up audio path interconnects */ | 690 | /* set up audio path interconnects */ |
| 643 | for (i = 0; intercon[i][0] != NULL; i++) | 691 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
| 644 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
| 645 | intercon[i][1], intercon[i][2]); | ||
| 646 | 692 | ||
| 647 | snd_soc_dapm_new_widgets(codec); | 693 | snd_soc_dapm_new_widgets(codec); |
| 648 | return 0; | 694 | return 0; |
| 649 | } | 695 | } |
| 650 | 696 | ||
| 651 | struct aic3x_rate_divs { | ||
| 652 | u32 mclk; | ||
| 653 | u32 rate; | ||
| 654 | u32 fsref_reg; | ||
| 655 | u8 sr_reg:4; | ||
| 656 | u8 pllj_reg; | ||
| 657 | u16 plld_reg; | ||
| 658 | }; | ||
| 659 | |||
| 660 | /* AIC3X codec mclk clock divider coefficients */ | ||
| 661 | static const struct aic3x_rate_divs aic3x_divs[] = { | ||
| 662 | /* 8k */ | ||
| 663 | {12000000, 8000, 48000, 0xa, 16, 3840}, | ||
| 664 | {19200000, 8000, 48000, 0xa, 10, 2400}, | ||
| 665 | {22579200, 8000, 48000, 0xa, 8, 7075}, | ||
| 666 | {33868800, 8000, 48000, 0xa, 5, 8049}, | ||
| 667 | /* 11.025k */ | ||
| 668 | {12000000, 11025, 44100, 0x6, 15, 528}, | ||
| 669 | {19200000, 11025, 44100, 0x6, 9, 4080}, | ||
| 670 | {22579200, 11025, 44100, 0x6, 8, 0}, | ||
| 671 | {33868800, 11025, 44100, 0x6, 5, 3333}, | ||
| 672 | /* 16k */ | ||
| 673 | {12000000, 16000, 48000, 0x4, 16, 3840}, | ||
| 674 | {19200000, 16000, 48000, 0x4, 10, 2400}, | ||
| 675 | {22579200, 16000, 48000, 0x4, 8, 7075}, | ||
| 676 | {33868800, 16000, 48000, 0x4, 5, 8049}, | ||
| 677 | /* 22.05k */ | ||
| 678 | {12000000, 22050, 44100, 0x2, 15, 528}, | ||
| 679 | {19200000, 22050, 44100, 0x2, 9, 4080}, | ||
| 680 | {22579200, 22050, 44100, 0x2, 8, 0}, | ||
| 681 | {33868800, 22050, 44100, 0x2, 5, 3333}, | ||
| 682 | /* 32k */ | ||
| 683 | {12000000, 32000, 48000, 0x1, 16, 3840}, | ||
| 684 | {19200000, 32000, 48000, 0x1, 10, 2400}, | ||
| 685 | {22579200, 32000, 48000, 0x1, 8, 7075}, | ||
| 686 | {33868800, 32000, 48000, 0x1, 5, 8049}, | ||
| 687 | /* 44.1k */ | ||
| 688 | {12000000, 44100, 44100, 0x0, 15, 528}, | ||
| 689 | {19200000, 44100, 44100, 0x0, 9, 4080}, | ||
| 690 | {22579200, 44100, 44100, 0x0, 8, 0}, | ||
| 691 | {33868800, 44100, 44100, 0x0, 5, 3333}, | ||
| 692 | /* 48k */ | ||
| 693 | {12000000, 48000, 48000, 0x0, 16, 3840}, | ||
| 694 | {19200000, 48000, 48000, 0x0, 10, 2400}, | ||
| 695 | {22579200, 48000, 48000, 0x0, 8, 7075}, | ||
| 696 | {33868800, 48000, 48000, 0x0, 5, 8049}, | ||
| 697 | /* 64k */ | ||
| 698 | {12000000, 64000, 96000, 0x1, 16, 3840}, | ||
| 699 | {19200000, 64000, 96000, 0x1, 10, 2400}, | ||
| 700 | {22579200, 64000, 96000, 0x1, 8, 7075}, | ||
| 701 | {33868800, 64000, 96000, 0x1, 5, 8049}, | ||
| 702 | /* 88.2k */ | ||
| 703 | {12000000, 88200, 88200, 0x0, 15, 528}, | ||
| 704 | {19200000, 88200, 88200, 0x0, 9, 4080}, | ||
| 705 | {22579200, 88200, 88200, 0x0, 8, 0}, | ||
| 706 | {33868800, 88200, 88200, 0x0, 5, 3333}, | ||
| 707 | /* 96k */ | ||
| 708 | {12000000, 96000, 96000, 0x0, 16, 3840}, | ||
| 709 | {19200000, 96000, 96000, 0x0, 10, 2400}, | ||
| 710 | {22579200, 96000, 96000, 0x0, 8, 7075}, | ||
| 711 | {33868800, 96000, 96000, 0x0, 5, 8049}, | ||
| 712 | }; | ||
| 713 | |||
| 714 | static inline int aic3x_get_divs(int mclk, int rate) | ||
| 715 | { | ||
| 716 | int i; | ||
| 717 | |||
| 718 | for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) { | ||
| 719 | if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk) | ||
| 720 | return i; | ||
| 721 | } | ||
| 722 | |||
| 723 | return 0; | ||
| 724 | } | ||
| 725 | |||
| 726 | static int aic3x_hw_params(struct snd_pcm_substream *substream, | 697 | static int aic3x_hw_params(struct snd_pcm_substream *substream, |
| 727 | struct snd_pcm_hw_params *params) | 698 | struct snd_pcm_hw_params *params) |
| 728 | { | 699 | { |
| @@ -730,49 +701,107 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
| 730 | struct snd_soc_device *socdev = rtd->socdev; | 701 | struct snd_soc_device *socdev = rtd->socdev; |
| 731 | struct snd_soc_codec *codec = socdev->codec; | 702 | struct snd_soc_codec *codec = socdev->codec; |
| 732 | struct aic3x_priv *aic3x = codec->private_data; | 703 | struct aic3x_priv *aic3x = codec->private_data; |
| 733 | int i; | 704 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
| 734 | u8 data, pll_p, pll_r, pll_j; | 705 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
| 735 | u16 pll_d; | 706 | u16 pll_d = 1; |
| 736 | |||
| 737 | i = aic3x_get_divs(aic3x->sysclk, params_rate(params)); | ||
| 738 | 707 | ||
| 739 | /* Route Left DAC to left channel input and | 708 | /* select data word length */ |
| 740 | * right DAC to right channel input */ | 709 | data = |
| 741 | data = (LDAC2LCH | RDAC2RCH); | 710 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); |
| 742 | switch (aic3x_divs[i].fsref_reg) { | 711 | switch (params_format(params)) { |
| 743 | case 44100: | 712 | case SNDRV_PCM_FORMAT_S16_LE: |
| 744 | data |= FSREF_44100; | ||
| 745 | break; | 713 | break; |
| 746 | case 48000: | 714 | case SNDRV_PCM_FORMAT_S20_3LE: |
| 747 | data |= FSREF_48000; | 715 | data |= (0x01 << 4); |
| 748 | break; | 716 | break; |
| 749 | case 88200: | 717 | case SNDRV_PCM_FORMAT_S24_LE: |
| 750 | data |= FSREF_44100 | DUAL_RATE_MODE; | 718 | data |= (0x02 << 4); |
| 751 | break; | 719 | break; |
| 752 | case 96000: | 720 | case SNDRV_PCM_FORMAT_S32_LE: |
| 753 | data |= FSREF_48000 | DUAL_RATE_MODE; | 721 | data |= (0x03 << 4); |
| 754 | break; | 722 | break; |
| 755 | } | 723 | } |
| 724 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
| 725 | |||
| 726 | /* Fsref can be 44100 or 48000 */ | ||
| 727 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; | ||
| 728 | |||
| 729 | /* Try to find a value for Q which allows us to bypass the PLL and | ||
| 730 | * generate CODEC_CLK directly. */ | ||
| 731 | for (pll_q = 2; pll_q < 18; pll_q++) | ||
| 732 | if (aic3x->sysclk / (128 * pll_q) == fsref) { | ||
| 733 | bypass_pll = 1; | ||
| 734 | break; | ||
| 735 | } | ||
| 736 | |||
| 737 | if (bypass_pll) { | ||
| 738 | pll_q &= 0xf; | ||
| 739 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); | ||
| 740 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); | ||
| 741 | } else | ||
| 742 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); | ||
| 743 | |||
| 744 | /* Route Left DAC to left channel input and | ||
| 745 | * right DAC to right channel input */ | ||
| 746 | data = (LDAC2LCH | RDAC2RCH); | ||
| 747 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; | ||
| 748 | if (params_rate(params) >= 64000) | ||
| 749 | data |= DUAL_RATE_MODE; | ||
| 756 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); | 750 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); |
| 757 | 751 | ||
| 758 | /* codec sample rate select */ | 752 | /* codec sample rate select */ |
| 759 | data = aic3x_divs[i].sr_reg; | 753 | data = (fsref * 20) / params_rate(params); |
| 754 | if (params_rate(params) < 64000) | ||
| 755 | data /= 2; | ||
| 756 | data /= 5; | ||
| 757 | data -= 2; | ||
| 760 | data |= (data << 4); | 758 | data |= (data << 4); |
| 761 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); | 759 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); |
| 762 | 760 | ||
| 763 | /* Use PLL for generation Fsref by equation: | 761 | if (bypass_pll) |
| 764 | * Fsref = (MCLK * K * R)/(2048 * P); | 762 | return 0; |
| 765 | * Fix P = 2 and R = 1 and calculate K, if | 763 | |
| 766 | * K = J.D, i.e. J - an interger portion of K and D is the fractional | 764 | /* Use PLL |
| 767 | * one with 4 digits of precision; | 765 | * find an apropriate setup for j, d, r and p by iterating over |
| 768 | * Example: | 766 | * p and r - j and d are calculated for each fraction. |
| 769 | * For MCLK = 22.5792 MHz and Fsref = 48kHz: | 767 | * Up to 128 values are probed, the closest one wins the game. |
| 770 | * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074 | 768 | * The sysclk is divided by 1000 to prevent integer overflows. |
| 771 | */ | 769 | */ |
| 772 | pll_p = 2; | 770 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); |
| 773 | pll_r = 1; | 771 | |
| 774 | pll_j = aic3x_divs[i].pllj_reg; | 772 | for (r = 1; r <= 16; r++) |
| 775 | pll_d = aic3x_divs[i].plld_reg; | 773 | for (p = 1; p <= 8; p++) { |
| 774 | int clk, tmp = (codec_clk * pll_r * 10) / pll_p; | ||
| 775 | u8 j = tmp / 10000; | ||
| 776 | u16 d = tmp % 10000; | ||
| 777 | |||
| 778 | if (j > 63) | ||
| 779 | continue; | ||
| 780 | |||
| 781 | if (d != 0 && aic3x->sysclk < 10000000) | ||
| 782 | continue; | ||
| 783 | |||
| 784 | /* This is actually 1000 * ((j + (d/10000)) * r) / p | ||
| 785 | * The term had to be converted to get rid of the | ||
| 786 | * division by 10000 */ | ||
| 787 | clk = ((10000 * j * r) + (d * r)) / (10 * p); | ||
| 788 | |||
| 789 | /* check whether this values get closer than the best | ||
| 790 | * ones we had before */ | ||
| 791 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { | ||
| 792 | pll_j = j; pll_d = d; pll_r = r; pll_p = p; | ||
| 793 | last_clk = clk; | ||
| 794 | } | ||
| 795 | |||
| 796 | /* Early exit for exact matches */ | ||
| 797 | if (clk == codec_clk) | ||
| 798 | break; | ||
| 799 | } | ||
| 800 | |||
| 801 | if (last_clk == 0) { | ||
| 802 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); | ||
| 803 | return -EINVAL; | ||
| 804 | } | ||
| 776 | 805 | ||
| 777 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 806 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
| 778 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); | 807 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); |
| @@ -782,28 +811,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
| 782 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, | 811 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, |
| 783 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | 812 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); |
| 784 | 813 | ||
| 785 | /* select data word length */ | ||
| 786 | data = | ||
| 787 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); | ||
| 788 | switch (params_format(params)) { | ||
| 789 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 790 | break; | ||
| 791 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
| 792 | data |= (0x01 << 4); | ||
| 793 | break; | ||
| 794 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 795 | data |= (0x02 << 4); | ||
| 796 | break; | ||
| 797 | case SNDRV_PCM_FORMAT_S32_LE: | ||
| 798 | data |= (0x03 << 4); | ||
| 799 | break; | ||
| 800 | } | ||
| 801 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
| 802 | |||
| 803 | return 0; | 814 | return 0; |
| 804 | } | 815 | } |
| 805 | 816 | ||
| 806 | static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) | 817 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) |
| 807 | { | 818 | { |
| 808 | struct snd_soc_codec *codec = dai->codec; | 819 | struct snd_soc_codec *codec = dai->codec; |
| 809 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; | 820 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; |
| @@ -820,31 +831,25 @@ static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) | |||
| 820 | return 0; | 831 | return 0; |
| 821 | } | 832 | } |
| 822 | 833 | ||
| 823 | static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 834 | static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
| 824 | int clk_id, unsigned int freq, int dir) | 835 | int clk_id, unsigned int freq, int dir) |
| 825 | { | 836 | { |
| 826 | struct snd_soc_codec *codec = codec_dai->codec; | 837 | struct snd_soc_codec *codec = codec_dai->codec; |
| 827 | struct aic3x_priv *aic3x = codec->private_data; | 838 | struct aic3x_priv *aic3x = codec->private_data; |
| 828 | 839 | ||
| 829 | switch (freq) { | 840 | aic3x->sysclk = freq; |
| 830 | case 12000000: | 841 | return 0; |
| 831 | case 19200000: | ||
| 832 | case 22579200: | ||
| 833 | case 33868800: | ||
| 834 | aic3x->sysclk = freq; | ||
| 835 | return 0; | ||
| 836 | } | ||
| 837 | |||
| 838 | return -EINVAL; | ||
| 839 | } | 842 | } |
| 840 | 843 | ||
| 841 | static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 844 | static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 842 | unsigned int fmt) | 845 | unsigned int fmt) |
| 843 | { | 846 | { |
| 844 | struct snd_soc_codec *codec = codec_dai->codec; | 847 | struct snd_soc_codec *codec = codec_dai->codec; |
| 845 | struct aic3x_priv *aic3x = codec->private_data; | 848 | struct aic3x_priv *aic3x = codec->private_data; |
| 846 | u8 iface_areg = 0; | 849 | u8 iface_areg, iface_breg; |
| 847 | u8 iface_breg = 0; | 850 | |
| 851 | iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; | ||
| 852 | iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; | ||
| 848 | 853 | ||
| 849 | /* set master/slave audio interface */ | 854 | /* set master/slave audio interface */ |
| 850 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 855 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
| @@ -883,13 +888,14 @@ static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 883 | return 0; | 888 | return 0; |
| 884 | } | 889 | } |
| 885 | 890 | ||
| 886 | static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | 891 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, |
| 892 | enum snd_soc_bias_level level) | ||
| 887 | { | 893 | { |
| 888 | struct aic3x_priv *aic3x = codec->private_data; | 894 | struct aic3x_priv *aic3x = codec->private_data; |
| 889 | u8 reg; | 895 | u8 reg; |
| 890 | 896 | ||
| 891 | switch (event) { | 897 | switch (level) { |
| 892 | case SNDRV_CTL_POWER_D0: | 898 | case SND_SOC_BIAS_ON: |
| 893 | /* all power is driven by DAPM system */ | 899 | /* all power is driven by DAPM system */ |
| 894 | if (aic3x->master) { | 900 | if (aic3x->master) { |
| 895 | /* enable pll */ | 901 | /* enable pll */ |
| @@ -898,10 +904,9 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
| 898 | reg | PLL_ENABLE); | 904 | reg | PLL_ENABLE); |
| 899 | } | 905 | } |
| 900 | break; | 906 | break; |
| 901 | case SNDRV_CTL_POWER_D1: | 907 | case SND_SOC_BIAS_PREPARE: |
| 902 | case SNDRV_CTL_POWER_D2: | ||
| 903 | break; | 908 | break; |
| 904 | case SNDRV_CTL_POWER_D3hot: | 909 | case SND_SOC_BIAS_STANDBY: |
| 905 | /* | 910 | /* |
| 906 | * all power is driven by DAPM system, | 911 | * all power is driven by DAPM system, |
| 907 | * so output power is safe if bypass was set | 912 | * so output power is safe if bypass was set |
| @@ -913,7 +918,7 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
| 913 | reg & ~PLL_ENABLE); | 918 | reg & ~PLL_ENABLE); |
| 914 | } | 919 | } |
| 915 | break; | 920 | break; |
| 916 | case SNDRV_CTL_POWER_D3cold: | 921 | case SND_SOC_BIAS_OFF: |
| 917 | /* force all power off */ | 922 | /* force all power off */ |
| 918 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); | 923 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); |
| 919 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); | 924 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); |
| @@ -949,16 +954,43 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
| 949 | } | 954 | } |
| 950 | break; | 955 | break; |
| 951 | } | 956 | } |
| 952 | codec->dapm_state = event; | 957 | codec->bias_level = level; |
| 953 | 958 | ||
| 954 | return 0; | 959 | return 0; |
| 955 | } | 960 | } |
| 956 | 961 | ||
| 962 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) | ||
| 963 | { | ||
| 964 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | ||
| 965 | u8 bit = gpio ? 3: 0; | ||
| 966 | u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); | ||
| 967 | aic3x_write(codec, reg, val | (!!state << bit)); | ||
| 968 | } | ||
| 969 | EXPORT_SYMBOL_GPL(aic3x_set_gpio); | ||
| 970 | |||
| 971 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) | ||
| 972 | { | ||
| 973 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | ||
| 974 | u8 val, bit = gpio ? 2: 1; | ||
| 975 | |||
| 976 | aic3x_read(codec, reg, &val); | ||
| 977 | return (val >> bit) & 1; | ||
| 978 | } | ||
| 979 | EXPORT_SYMBOL_GPL(aic3x_get_gpio); | ||
| 980 | |||
| 981 | int aic3x_headset_detected(struct snd_soc_codec *codec) | ||
| 982 | { | ||
| 983 | u8 val; | ||
| 984 | aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); | ||
| 985 | return (val >> 2) & 1; | ||
| 986 | } | ||
| 987 | EXPORT_SYMBOL_GPL(aic3x_headset_detected); | ||
| 988 | |||
| 957 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 | 989 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 |
| 958 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 990 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
| 959 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 991 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
| 960 | 992 | ||
| 961 | struct snd_soc_codec_dai aic3x_dai = { | 993 | struct snd_soc_dai aic3x_dai = { |
| 962 | .name = "aic3x", | 994 | .name = "aic3x", |
| 963 | .playback = { | 995 | .playback = { |
| 964 | .stream_name = "Playback", | 996 | .stream_name = "Playback", |
| @@ -988,7 +1020,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 988 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1020 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 989 | struct snd_soc_codec *codec = socdev->codec; | 1021 | struct snd_soc_codec *codec = socdev->codec; |
| 990 | 1022 | ||
| 991 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1023 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 992 | 1024 | ||
| 993 | return 0; | 1025 | return 0; |
| 994 | } | 1026 | } |
| @@ -1008,7 +1040,7 @@ static int aic3x_resume(struct platform_device *pdev) | |||
| 1008 | codec->hw_write(codec->control_data, data, 2); | 1040 | codec->hw_write(codec->control_data, data, 2); |
| 1009 | } | 1041 | } |
| 1010 | 1042 | ||
| 1011 | aic3x_dapm_event(codec, codec->suspend_dapm_state); | 1043 | aic3x_set_bias_level(codec, codec->suspend_bias_level); |
| 1012 | 1044 | ||
| 1013 | return 0; | 1045 | return 0; |
| 1014 | } | 1046 | } |
| @@ -1020,16 +1052,17 @@ static int aic3x_resume(struct platform_device *pdev) | |||
| 1020 | static int aic3x_init(struct snd_soc_device *socdev) | 1052 | static int aic3x_init(struct snd_soc_device *socdev) |
| 1021 | { | 1053 | { |
| 1022 | struct snd_soc_codec *codec = socdev->codec; | 1054 | struct snd_soc_codec *codec = socdev->codec; |
| 1055 | struct aic3x_setup_data *setup = socdev->codec_data; | ||
| 1023 | int reg, ret = 0; | 1056 | int reg, ret = 0; |
| 1024 | 1057 | ||
| 1025 | codec->name = "aic3x"; | 1058 | codec->name = "aic3x"; |
| 1026 | codec->owner = THIS_MODULE; | 1059 | codec->owner = THIS_MODULE; |
| 1027 | codec->read = aic3x_read_reg_cache; | 1060 | codec->read = aic3x_read_reg_cache; |
| 1028 | codec->write = aic3x_write; | 1061 | codec->write = aic3x_write; |
| 1029 | codec->dapm_event = aic3x_dapm_event; | 1062 | codec->set_bias_level = aic3x_set_bias_level; |
| 1030 | codec->dai = &aic3x_dai; | 1063 | codec->dai = &aic3x_dai; |
| 1031 | codec->num_dai = 1; | 1064 | codec->num_dai = 1; |
| 1032 | codec->reg_cache_size = sizeof(aic3x_reg); | 1065 | codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); |
| 1033 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); | 1066 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); |
| 1034 | if (codec->reg_cache == NULL) | 1067 | if (codec->reg_cache == NULL) |
| 1035 | return -ENOMEM; | 1068 | return -ENOMEM; |
| @@ -1108,7 +1141,11 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
| 1108 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | 1141 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); |
| 1109 | 1142 | ||
| 1110 | /* off, with power on */ | 1143 | /* off, with power on */ |
| 1111 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1144 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1145 | |||
| 1146 | /* setup GPIO functions */ | ||
| 1147 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); | ||
| 1148 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); | ||
| 1112 | 1149 | ||
| 1113 | aic3x_add_controls(codec); | 1150 | aic3x_add_controls(codec); |
| 1114 | aic3x_add_widgets(codec); | 1151 | aic3x_add_widgets(codec); |
| @@ -1217,6 +1254,12 @@ static struct i2c_client client_template = { | |||
| 1217 | .name = "AIC3X", | 1254 | .name = "AIC3X", |
| 1218 | .driver = &aic3x_i2c_driver, | 1255 | .driver = &aic3x_i2c_driver, |
| 1219 | }; | 1256 | }; |
| 1257 | |||
| 1258 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | ||
| 1259 | { | ||
| 1260 | value[0] = i2c_smbus_read_byte_data(client, value[0]); | ||
| 1261 | return (len == 1); | ||
| 1262 | } | ||
| 1220 | #endif | 1263 | #endif |
| 1221 | 1264 | ||
| 1222 | static int aic3x_probe(struct platform_device *pdev) | 1265 | static int aic3x_probe(struct platform_device *pdev) |
| @@ -1251,6 +1294,7 @@ static int aic3x_probe(struct platform_device *pdev) | |||
| 1251 | if (setup->i2c_address) { | 1294 | if (setup->i2c_address) { |
| 1252 | normal_i2c[0] = setup->i2c_address; | 1295 | normal_i2c[0] = setup->i2c_address; |
| 1253 | codec->hw_write = (hw_write_t) i2c_master_send; | 1296 | codec->hw_write = (hw_write_t) i2c_master_send; |
| 1297 | codec->hw_read = (hw_read_t) aic3x_i2c_read; | ||
| 1254 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1298 | ret = i2c_add_driver(&aic3x_i2c_driver); |
| 1255 | if (ret != 0) | 1299 | if (ret != 0) |
| 1256 | printk(KERN_ERR "can't add i2c driver"); | 1300 | printk(KERN_ERR "can't add i2c driver"); |
| @@ -1268,7 +1312,7 @@ static int aic3x_remove(struct platform_device *pdev) | |||
| 1268 | 1312 | ||
| 1269 | /* power down chip */ | 1313 | /* power down chip */ |
| 1270 | if (codec->control_data) | 1314 | if (codec->control_data) |
| 1271 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3); | 1315 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1272 | 1316 | ||
| 1273 | snd_soc_free_pcms(socdev); | 1317 | snd_soc_free_pcms(socdev); |
| 1274 | snd_soc_dapm_free(socdev); | 1318 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index d0cdeeb629de..d76c079b86e7 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
| @@ -37,6 +37,8 @@ | |||
| 37 | #define AIC3X_ASD_INTF_CTRLB 9 | 37 | #define AIC3X_ASD_INTF_CTRLB 9 |
| 38 | /* Audio overflow status and PLL R value programming register */ | 38 | /* Audio overflow status and PLL R value programming register */ |
| 39 | #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 | 39 | #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 |
| 40 | /* Audio codec digital filter control register */ | ||
| 41 | #define AIC3X_CODEC_DFILT_CTRL 12 | ||
| 40 | 42 | ||
| 41 | /* ADC PGA Gain control registers */ | 43 | /* ADC PGA Gain control registers */ |
| 42 | #define LADC_VOL 15 | 44 | #define LADC_VOL 15 |
| @@ -108,6 +110,13 @@ | |||
| 108 | #define DACR1_2_RLOPM_VOL 92 | 110 | #define DACR1_2_RLOPM_VOL 92 |
| 109 | #define LLOPM_CTRL 86 | 111 | #define LLOPM_CTRL 86 |
| 110 | #define RLOPM_CTRL 93 | 112 | #define RLOPM_CTRL 93 |
| 113 | /* GPIO/IRQ registers */ | ||
| 114 | #define AIC3X_STICKY_IRQ_FLAGS_REG 96 | ||
| 115 | #define AIC3X_RT_IRQ_FLAGS_REG 97 | ||
| 116 | #define AIC3X_GPIO1_REG 98 | ||
| 117 | #define AIC3X_GPIO2_REG 99 | ||
| 118 | #define AIC3X_GPIOA_REG 100 | ||
| 119 | #define AIC3X_GPIOB_REG 101 | ||
| 111 | /* Clock generation control register */ | 120 | /* Clock generation control register */ |
| 112 | #define AIC3X_CLKGEN_CTRL_REG 102 | 121 | #define AIC3X_CLKGEN_CTRL_REG 102 |
| 113 | 122 | ||
| @@ -128,12 +137,15 @@ | |||
| 128 | 137 | ||
| 129 | /* PLL registers bitfields */ | 138 | /* PLL registers bitfields */ |
| 130 | #define PLLP_SHIFT 0 | 139 | #define PLLP_SHIFT 0 |
| 140 | #define PLLQ_SHIFT 3 | ||
| 131 | #define PLLR_SHIFT 0 | 141 | #define PLLR_SHIFT 0 |
| 132 | #define PLLJ_SHIFT 2 | 142 | #define PLLJ_SHIFT 2 |
| 133 | #define PLLD_MSB_SHIFT 0 | 143 | #define PLLD_MSB_SHIFT 0 |
| 134 | #define PLLD_LSB_SHIFT 2 | 144 | #define PLLD_LSB_SHIFT 2 |
| 135 | 145 | ||
| 136 | /* Clock generation register bits */ | 146 | /* Clock generation register bits */ |
| 147 | #define CODEC_CLKIN_PLLDIV 0 | ||
| 148 | #define CODEC_CLKIN_CLKDIV 1 | ||
| 137 | #define PLL_CLKIN_SHIFT 4 | 149 | #define PLL_CLKIN_SHIFT 4 |
| 138 | #define MCLK_SOURCE 0x0 | 150 | #define MCLK_SOURCE 0x0 |
| 139 | #define PLL_CLKDIV_SHIFT 0 | 151 | #define PLL_CLKDIV_SHIFT 0 |
| @@ -171,11 +183,52 @@ | |||
| 171 | /* Default input volume */ | 183 | /* Default input volume */ |
| 172 | #define DEFAULT_GAIN 0x20 | 184 | #define DEFAULT_GAIN 0x20 |
| 173 | 185 | ||
| 186 | /* GPIO API */ | ||
| 187 | enum { | ||
| 188 | AIC3X_GPIO1_FUNC_DISABLED = 0, | ||
| 189 | AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1, | ||
| 190 | AIC3X_GPIO1_FUNC_CLOCK_MUX = 2, | ||
| 191 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3, | ||
| 192 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4, | ||
| 193 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5, | ||
| 194 | AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6, | ||
| 195 | AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7, | ||
| 196 | AIC3X_GPIO1_FUNC_INPUT = 8, | ||
| 197 | AIC3X_GPIO1_FUNC_OUTPUT = 9, | ||
| 198 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10, | ||
| 199 | AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11, | ||
| 200 | AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12, | ||
| 201 | AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13, | ||
| 202 | AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14, | ||
| 203 | AIC3X_GPIO1_FUNC_ALL_IRQ = 16 | ||
| 204 | }; | ||
| 205 | |||
| 206 | enum { | ||
| 207 | AIC3X_GPIO2_FUNC_DISABLED = 0, | ||
| 208 | AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2, | ||
| 209 | AIC3X_GPIO2_FUNC_INPUT = 3, | ||
| 210 | AIC3X_GPIO2_FUNC_OUTPUT = 4, | ||
| 211 | AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5, | ||
| 212 | AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8, | ||
| 213 | AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9, | ||
| 214 | AIC3X_GPIO2_FUNC_ALL_IRQ = 10, | ||
| 215 | AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11, | ||
| 216 | AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12, | ||
| 217 | AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13, | ||
| 218 | AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14, | ||
| 219 | AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 | ||
| 220 | }; | ||
| 221 | |||
| 222 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); | ||
| 223 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); | ||
| 224 | int aic3x_headset_detected(struct snd_soc_codec *codec); | ||
| 225 | |||
| 174 | struct aic3x_setup_data { | 226 | struct aic3x_setup_data { |
| 175 | unsigned short i2c_address; | 227 | unsigned short i2c_address; |
| 228 | unsigned int gpio_func[2]; | ||
| 176 | }; | 229 | }; |
| 177 | 230 | ||
| 178 | extern struct snd_soc_codec_dai aic3x_dai; | 231 | extern struct snd_soc_dai aic3x_dai; |
| 179 | extern struct snd_soc_codec_device soc_codec_dev_aic3x; | 232 | extern struct snd_soc_codec_device soc_codec_dev_aic3x; |
| 180 | 233 | ||
| 181 | #endif /* _AIC3X_H */ | 234 | #endif /* _AIC3X_H */ |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c new file mode 100644 index 000000000000..a52d6d9e007a --- /dev/null +++ b/sound/soc/codecs/uda1380.c | |||
| @@ -0,0 +1,852 @@ | |||
| 1 | /* | ||
| 2 | * uda1380.c - Philips UDA1380 ALSA SoC audio driver | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> | ||
| 9 | * Improved support for DAPM and audio routing/mixing capabilities, | ||
| 10 | * added TLV support. | ||
| 11 | * | ||
| 12 | * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC | ||
| 13 | * codec model. | ||
| 14 | * | ||
| 15 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> | ||
| 16 | * Copyright 2005 Openedhand Ltd. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/string.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/errno.h> | ||
| 25 | #include <linux/ioctl.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include <sound/core.h> | ||
| 29 | #include <sound/control.h> | ||
| 30 | #include <sound/initval.h> | ||
| 31 | #include <sound/info.h> | ||
| 32 | #include <sound/soc.h> | ||
| 33 | #include <sound/soc-dapm.h> | ||
| 34 | #include <sound/tlv.h> | ||
| 35 | |||
| 36 | #include "uda1380.h" | ||
| 37 | |||
| 38 | #define UDA1380_VERSION "0.6" | ||
| 39 | #define AUDIO_NAME "uda1380" | ||
| 40 | |||
| 41 | /* | ||
| 42 | * uda1380 register cache | ||
| 43 | */ | ||
| 44 | static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { | ||
| 45 | 0x0502, 0x0000, 0x0000, 0x3f3f, | ||
| 46 | 0x0202, 0x0000, 0x0000, 0x0000, | ||
| 47 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 48 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 49 | 0x0000, 0xff00, 0x0000, 0x4800, | ||
| 50 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 51 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 52 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 53 | 0x0000, 0x8000, 0x0002, 0x0000, | ||
| 54 | }; | ||
| 55 | |||
| 56 | /* | ||
| 57 | * read uda1380 register cache | ||
| 58 | */ | ||
| 59 | static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, | ||
| 60 | unsigned int reg) | ||
| 61 | { | ||
| 62 | u16 *cache = codec->reg_cache; | ||
| 63 | if (reg == UDA1380_RESET) | ||
| 64 | return 0; | ||
| 65 | if (reg >= UDA1380_CACHEREGNUM) | ||
| 66 | return -1; | ||
| 67 | return cache[reg]; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * write uda1380 register cache | ||
| 72 | */ | ||
| 73 | static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, | ||
| 74 | u16 reg, unsigned int value) | ||
| 75 | { | ||
| 76 | u16 *cache = codec->reg_cache; | ||
| 77 | if (reg >= UDA1380_CACHEREGNUM) | ||
| 78 | return; | ||
| 79 | cache[reg] = value; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* | ||
| 83 | * write to the UDA1380 register space | ||
| 84 | */ | ||
| 85 | static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | ||
| 86 | unsigned int value) | ||
| 87 | { | ||
| 88 | u8 data[3]; | ||
| 89 | |||
| 90 | /* data is | ||
| 91 | * data[0] is register offset | ||
| 92 | * data[1] is MS byte | ||
| 93 | * data[2] is LS byte | ||
| 94 | */ | ||
| 95 | data[0] = reg; | ||
| 96 | data[1] = (value & 0xff00) >> 8; | ||
| 97 | data[2] = value & 0x00ff; | ||
| 98 | |||
| 99 | uda1380_write_reg_cache(codec, reg, value); | ||
| 100 | |||
| 101 | /* the interpolator & decimator regs must only be written when the | ||
| 102 | * codec DAI is active. | ||
| 103 | */ | ||
| 104 | if (!codec->active && (reg >= UDA1380_MVOL)) | ||
| 105 | return 0; | ||
| 106 | pr_debug("uda1380: hw write %x val %x\n", reg, value); | ||
| 107 | if (codec->hw_write(codec->control_data, data, 3) == 3) { | ||
| 108 | unsigned int val; | ||
| 109 | i2c_master_send(codec->control_data, data, 1); | ||
| 110 | i2c_master_recv(codec->control_data, data, 2); | ||
| 111 | val = (data[0]<<8) | data[1]; | ||
| 112 | if (val != value) { | ||
| 113 | pr_debug("uda1380: READ BACK VAL %x\n", | ||
| 114 | (data[0]<<8) | data[1]); | ||
| 115 | return -EIO; | ||
| 116 | } | ||
| 117 | return 0; | ||
| 118 | } else | ||
| 119 | return -EIO; | ||
| 120 | } | ||
| 121 | |||
| 122 | #define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) | ||
| 123 | |||
| 124 | /* declarations of ALSA reg_elem_REAL controls */ | ||
| 125 | static const char *uda1380_deemp[] = { | ||
| 126 | "None", | ||
| 127 | "32kHz", | ||
| 128 | "44.1kHz", | ||
| 129 | "48kHz", | ||
| 130 | "96kHz", | ||
| 131 | }; | ||
| 132 | static const char *uda1380_input_sel[] = { | ||
| 133 | "Line", | ||
| 134 | "Mic + Line R", | ||
| 135 | "Line L", | ||
| 136 | "Mic", | ||
| 137 | }; | ||
| 138 | static const char *uda1380_output_sel[] = { | ||
| 139 | "DAC", | ||
| 140 | "Analog Mixer", | ||
| 141 | }; | ||
| 142 | static const char *uda1380_spf_mode[] = { | ||
| 143 | "Flat", | ||
| 144 | "Minimum1", | ||
| 145 | "Minimum2", | ||
| 146 | "Maximum" | ||
| 147 | }; | ||
| 148 | static const char *uda1380_capture_sel[] = { | ||
| 149 | "ADC", | ||
| 150 | "Digital Mixer" | ||
| 151 | }; | ||
| 152 | static const char *uda1380_sel_ns[] = { | ||
| 153 | "3rd-order", | ||
| 154 | "5th-order" | ||
| 155 | }; | ||
| 156 | static const char *uda1380_mix_control[] = { | ||
| 157 | "off", | ||
| 158 | "PCM only", | ||
| 159 | "before sound processing", | ||
| 160 | "after sound processing" | ||
| 161 | }; | ||
| 162 | static const char *uda1380_sdet_setting[] = { | ||
| 163 | "3200", | ||
| 164 | "4800", | ||
| 165 | "9600", | ||
| 166 | "19200" | ||
| 167 | }; | ||
| 168 | static const char *uda1380_os_setting[] = { | ||
| 169 | "single-speed", | ||
| 170 | "double-speed (no mixing)", | ||
| 171 | "quad-speed (no mixing)" | ||
| 172 | }; | ||
| 173 | |||
| 174 | static const struct soc_enum uda1380_deemp_enum[] = { | ||
| 175 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), | ||
| 176 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), | ||
| 177 | }; | ||
| 178 | static const struct soc_enum uda1380_input_sel_enum = | ||
| 179 | SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ | ||
| 180 | static const struct soc_enum uda1380_output_sel_enum = | ||
| 181 | SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */ | ||
| 182 | static const struct soc_enum uda1380_spf_enum = | ||
| 183 | SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */ | ||
| 184 | static const struct soc_enum uda1380_capture_sel_enum = | ||
| 185 | SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */ | ||
| 186 | static const struct soc_enum uda1380_sel_ns_enum = | ||
| 187 | SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */ | ||
| 188 | static const struct soc_enum uda1380_mix_enum = | ||
| 189 | SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */ | ||
| 190 | static const struct soc_enum uda1380_sdet_enum = | ||
| 191 | SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */ | ||
| 192 | static const struct soc_enum uda1380_os_enum = | ||
| 193 | SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */ | ||
| 194 | |||
| 195 | /* | ||
| 196 | * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) | ||
| 197 | */ | ||
| 198 | static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); | ||
| 199 | |||
| 200 | /* | ||
| 201 | * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored), | ||
| 202 | * from -66 dB in 0.5 dB steps (2 dB steps, really) and | ||
| 203 | * from -52 dB in 0.25 dB steps | ||
| 204 | */ | ||
| 205 | static const unsigned int mvol_tlv[] = { | ||
| 206 | TLV_DB_RANGE_HEAD(3), | ||
| 207 | 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), | ||
| 208 | 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), | ||
| 209 | 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0), | ||
| 210 | }; | ||
| 211 | |||
| 212 | /* | ||
| 213 | * from -72 dB in 1.5 dB steps (6 dB steps really), | ||
| 214 | * from -66 dB in 0.75 dB steps (3 dB steps really), | ||
| 215 | * from -60 dB in 0.5 dB steps (2 dB steps really) and | ||
| 216 | * from -46 dB in 0.25 dB steps | ||
| 217 | */ | ||
| 218 | static const unsigned int vc_tlv[] = { | ||
| 219 | TLV_DB_RANGE_HEAD(4), | ||
| 220 | 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), | ||
| 221 | 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), | ||
| 222 | 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), | ||
| 223 | 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0), | ||
| 224 | }; | ||
| 225 | |||
| 226 | /* from 0 to 6 dB in 2 dB steps if SPF mode != flat */ | ||
| 227 | static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0); | ||
| 228 | |||
| 229 | /* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts | ||
| 230 | * off at 18 dB max) */ | ||
| 231 | static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0); | ||
| 232 | |||
| 233 | /* from -63 to 24 dB in 0.5 dB steps (-128...48) */ | ||
| 234 | static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1); | ||
| 235 | |||
| 236 | /* from 0 to 24 dB in 3 dB steps */ | ||
| 237 | static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); | ||
| 238 | |||
| 239 | /* from 0 to 30 dB in 2 dB steps */ | ||
| 240 | static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0); | ||
| 241 | |||
| 242 | static const struct snd_kcontrol_new uda1380_snd_controls[] = { | ||
| 243 | SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv), /* AVCR, AVCL */ | ||
| 244 | SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv), /* MVCL, MVCR */ | ||
| 245 | SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv), /* VC2 */ | ||
| 246 | SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv), /* VC1 */ | ||
| 247 | SOC_ENUM("Sound Processing Filter", uda1380_spf_enum), /* M */ | ||
| 248 | SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv), /* TRL, TRR */ | ||
| 249 | SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv), /* BBL, BBR */ | ||
| 250 | /**/ SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1), /* MTM */ | ||
| 251 | SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1), /* MT2 from decimation filter */ | ||
| 252 | SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]), /* DE2 */ | ||
| 253 | SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1), /* MT1, from digital data input */ | ||
| 254 | SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]), /* DE1 */ | ||
| 255 | SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ | ||
| 256 | SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ | ||
| 257 | SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ | ||
| 258 | SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */ | ||
| 259 | SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ | ||
| 260 | SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ | ||
| 261 | SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ | ||
| 262 | SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv), /* ML_DEC, MR_DEC */ | ||
| 263 | /**/ SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1), /* MT_ADC */ | ||
| 264 | SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */ | ||
| 265 | SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0), /* ADCPOL_INV */ | ||
| 266 | SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv), /* VGA_CTRL */ | ||
| 267 | SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0), /* SKIP_DCFIL (before decimator) */ | ||
| 268 | SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0), /* EN_DCFIL (at output of decimator) */ | ||
| 269 | SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0), /* TODO: enum, see table 62 */ | ||
| 270 | SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1), /* AGC_LEVEL */ | ||
| 271 | /* -5.5, -8, -11.5, -14 dBFS */ | ||
| 272 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), | ||
| 273 | }; | ||
| 274 | |||
| 275 | /* add non dapm controls */ | ||
| 276 | static int uda1380_add_controls(struct snd_soc_codec *codec) | ||
| 277 | { | ||
| 278 | int err, i; | ||
| 279 | |||
| 280 | for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { | ||
| 281 | err = snd_ctl_add(codec->card, | ||
| 282 | snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); | ||
| 283 | if (err < 0) | ||
| 284 | return err; | ||
| 285 | } | ||
| 286 | |||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* Input mux */ | ||
| 291 | static const struct snd_kcontrol_new uda1380_input_mux_control = | ||
| 292 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); | ||
| 293 | |||
| 294 | /* Output mux */ | ||
| 295 | static const struct snd_kcontrol_new uda1380_output_mux_control = | ||
| 296 | SOC_DAPM_ENUM("Route", uda1380_output_sel_enum); | ||
| 297 | |||
| 298 | /* Capture mux */ | ||
| 299 | static const struct snd_kcontrol_new uda1380_capture_mux_control = | ||
| 300 | SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum); | ||
| 301 | |||
| 302 | |||
| 303 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { | ||
| 304 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
| 305 | &uda1380_input_mux_control), | ||
| 306 | SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0, | ||
| 307 | &uda1380_output_mux_control), | ||
| 308 | SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, | ||
| 309 | &uda1380_capture_mux_control), | ||
| 310 | SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0), | ||
| 311 | SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0), | ||
| 312 | SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0), | ||
| 313 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0), | ||
| 314 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0), | ||
| 315 | SND_SOC_DAPM_INPUT("VINM"), | ||
| 316 | SND_SOC_DAPM_INPUT("VINL"), | ||
| 317 | SND_SOC_DAPM_INPUT("VINR"), | ||
| 318 | SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0), | ||
| 319 | SND_SOC_DAPM_OUTPUT("VOUTLHP"), | ||
| 320 | SND_SOC_DAPM_OUTPUT("VOUTRHP"), | ||
| 321 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
| 322 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
| 323 | SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0), | ||
| 324 | SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0), | ||
| 325 | }; | ||
| 326 | |||
| 327 | static const struct snd_soc_dapm_route audio_map[] = { | ||
| 328 | |||
| 329 | /* output mux */ | ||
| 330 | {"HeadPhone Driver", NULL, "Output Mux"}, | ||
| 331 | {"VOUTR", NULL, "Output Mux"}, | ||
| 332 | {"VOUTL", NULL, "Output Mux"}, | ||
| 333 | |||
| 334 | {"Analog Mixer", NULL, "VINR"}, | ||
| 335 | {"Analog Mixer", NULL, "VINL"}, | ||
| 336 | {"Analog Mixer", NULL, "DAC"}, | ||
| 337 | |||
| 338 | {"Output Mux", "DAC", "DAC"}, | ||
| 339 | {"Output Mux", "Analog Mixer", "Analog Mixer"}, | ||
| 340 | |||
| 341 | /* {"DAC", "Digital Mixer", "I2S" } */ | ||
| 342 | |||
| 343 | /* headphone driver */ | ||
| 344 | {"VOUTLHP", NULL, "HeadPhone Driver"}, | ||
| 345 | {"VOUTRHP", NULL, "HeadPhone Driver"}, | ||
| 346 | |||
| 347 | /* input mux */ | ||
| 348 | {"Left ADC", NULL, "Input Mux"}, | ||
| 349 | {"Input Mux", "Mic", "Mic LNA"}, | ||
| 350 | {"Input Mux", "Mic + Line R", "Mic LNA"}, | ||
| 351 | {"Input Mux", "Line L", "Left PGA"}, | ||
| 352 | {"Input Mux", "Line", "Left PGA"}, | ||
| 353 | |||
| 354 | /* right input */ | ||
| 355 | {"Right ADC", "Mic + Line R", "Right PGA"}, | ||
| 356 | {"Right ADC", "Line", "Right PGA"}, | ||
| 357 | |||
| 358 | /* inputs */ | ||
| 359 | {"Mic LNA", NULL, "VINM"}, | ||
| 360 | {"Left PGA", NULL, "VINL"}, | ||
| 361 | {"Right PGA", NULL, "VINR"}, | ||
| 362 | }; | ||
| 363 | |||
| 364 | static int uda1380_add_widgets(struct snd_soc_codec *codec) | ||
| 365 | { | ||
| 366 | snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets, | ||
| 367 | ARRAY_SIZE(uda1380_dapm_widgets)); | ||
| 368 | |||
| 369 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
| 370 | |||
| 371 | snd_soc_dapm_new_widgets(codec); | ||
| 372 | return 0; | ||
| 373 | } | ||
| 374 | |||
| 375 | static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
| 376 | unsigned int fmt) | ||
| 377 | { | ||
| 378 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 379 | int iface; | ||
| 380 | |||
| 381 | /* set up DAI based upon fmt */ | ||
| 382 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); | ||
| 383 | iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); | ||
| 384 | |||
| 385 | /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */ | ||
| 386 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 387 | case SND_SOC_DAIFMT_I2S: | ||
| 388 | iface |= R01_SFORI_I2S | R01_SFORO_I2S; | ||
| 389 | break; | ||
| 390 | case SND_SOC_DAIFMT_LSB: | ||
| 391 | iface |= R01_SFORI_LSB16 | R01_SFORO_I2S; | ||
| 392 | break; | ||
| 393 | case SND_SOC_DAIFMT_MSB: | ||
| 394 | iface |= R01_SFORI_MSB | R01_SFORO_I2S; | ||
| 395 | } | ||
| 396 | |||
| 397 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) | ||
| 398 | iface |= R01_SIM; | ||
| 399 | |||
| 400 | uda1380_write(codec, UDA1380_IFACE, iface); | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | /* | ||
| 406 | * Flush reg cache | ||
| 407 | * We can only write the interpolator and decimator registers | ||
| 408 | * when the DAI is being clocked by the CPU DAI. It's up to the | ||
| 409 | * machine and cpu DAI driver to do this before we are called. | ||
| 410 | */ | ||
| 411 | static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) | ||
| 412 | { | ||
| 413 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 414 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 415 | struct snd_soc_codec *codec = socdev->codec; | ||
| 416 | int reg, reg_start, reg_end, clk; | ||
| 417 | |||
| 418 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 419 | reg_start = UDA1380_MVOL; | ||
| 420 | reg_end = UDA1380_MIXER; | ||
| 421 | } else { | ||
| 422 | reg_start = UDA1380_DEC; | ||
| 423 | reg_end = UDA1380_AGC; | ||
| 424 | } | ||
| 425 | |||
| 426 | /* FIXME disable DAC_CLK */ | ||
| 427 | clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
| 428 | uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); | ||
| 429 | |||
| 430 | for (reg = reg_start; reg <= reg_end; reg++) { | ||
| 431 | pr_debug("uda1380: flush reg %x val %x:", reg, | ||
| 432 | uda1380_read_reg_cache(codec, reg)); | ||
| 433 | uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg)); | ||
| 434 | } | ||
| 435 | |||
| 436 | /* FIXME enable DAC_CLK */ | ||
| 437 | uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK); | ||
| 438 | |||
| 439 | return 0; | ||
| 440 | } | ||
| 441 | |||
| 442 | static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 443 | struct snd_pcm_hw_params *params) | ||
| 444 | { | ||
| 445 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 446 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 447 | struct snd_soc_codec *codec = socdev->codec; | ||
| 448 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
| 449 | |||
| 450 | /* set WSPLL power and divider if running from this clock */ | ||
| 451 | if (clk & R00_DAC_CLK) { | ||
| 452 | int rate = params_rate(params); | ||
| 453 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
| 454 | clk &= ~0x3; /* clear SEL_LOOP_DIV */ | ||
| 455 | switch (rate) { | ||
| 456 | case 6250 ... 12500: | ||
| 457 | clk |= 0x0; | ||
| 458 | break; | ||
| 459 | case 12501 ... 25000: | ||
| 460 | clk |= 0x1; | ||
| 461 | break; | ||
| 462 | case 25001 ... 50000: | ||
| 463 | clk |= 0x2; | ||
| 464 | break; | ||
| 465 | case 50001 ... 100000: | ||
| 466 | clk |= 0x3; | ||
| 467 | break; | ||
| 468 | } | ||
| 469 | uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm); | ||
| 470 | } | ||
| 471 | |||
| 472 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 473 | clk |= R00_EN_DAC | R00_EN_INT; | ||
| 474 | else | ||
| 475 | clk |= R00_EN_ADC | R00_EN_DEC; | ||
| 476 | |||
| 477 | uda1380_write(codec, UDA1380_CLK, clk); | ||
| 478 | return 0; | ||
| 479 | } | ||
| 480 | |||
| 481 | static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) | ||
| 482 | { | ||
| 483 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 484 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 485 | struct snd_soc_codec *codec = socdev->codec; | ||
| 486 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
| 487 | |||
| 488 | /* shut down WSPLL power if running from this clock */ | ||
| 489 | if (clk & R00_DAC_CLK) { | ||
| 490 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
| 491 | uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm); | ||
| 492 | } | ||
| 493 | |||
| 494 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 495 | clk &= ~(R00_EN_DAC | R00_EN_INT); | ||
| 496 | else | ||
| 497 | clk &= ~(R00_EN_ADC | R00_EN_DEC); | ||
| 498 | |||
| 499 | uda1380_write(codec, UDA1380_CLK, clk); | ||
| 500 | } | ||
| 501 | |||
| 502 | static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute) | ||
| 503 | { | ||
| 504 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 505 | u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM; | ||
| 506 | |||
| 507 | /* FIXME: mute(codec,0) is called when the magician clock is already | ||
| 508 | * set to WSPLL, but for some unknown reason writing to interpolator | ||
| 509 | * registers works only when clocked by SYSCLK */ | ||
| 510 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
| 511 | uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk); | ||
| 512 | if (mute) | ||
| 513 | uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM); | ||
| 514 | else | ||
| 515 | uda1380_write(codec, UDA1380_DEEMP, mute_reg); | ||
| 516 | uda1380_write(codec, UDA1380_CLK, clk); | ||
| 517 | return 0; | ||
| 518 | } | ||
| 519 | |||
| 520 | static int uda1380_set_bias_level(struct snd_soc_codec *codec, | ||
| 521 | enum snd_soc_bias_level level) | ||
| 522 | { | ||
| 523 | int pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
| 524 | |||
| 525 | switch (level) { | ||
| 526 | case SND_SOC_BIAS_ON: | ||
| 527 | case SND_SOC_BIAS_PREPARE: | ||
| 528 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); | ||
| 529 | break; | ||
| 530 | case SND_SOC_BIAS_STANDBY: | ||
| 531 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS); | ||
| 532 | break; | ||
| 533 | case SND_SOC_BIAS_OFF: | ||
| 534 | uda1380_write(codec, UDA1380_PM, 0x0); | ||
| 535 | break; | ||
| 536 | } | ||
| 537 | codec->bias_level = level; | ||
| 538 | return 0; | ||
| 539 | } | ||
| 540 | |||
| 541 | #define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
| 542 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
| 543 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
| 544 | |||
| 545 | struct snd_soc_dai uda1380_dai[] = { | ||
| 546 | { | ||
| 547 | .name = "UDA1380", | ||
| 548 | .playback = { | ||
| 549 | .stream_name = "Playback", | ||
| 550 | .channels_min = 1, | ||
| 551 | .channels_max = 2, | ||
| 552 | .rates = UDA1380_RATES, | ||
| 553 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
| 554 | .capture = { | ||
| 555 | .stream_name = "Capture", | ||
| 556 | .channels_min = 1, | ||
| 557 | .channels_max = 2, | ||
| 558 | .rates = UDA1380_RATES, | ||
| 559 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
| 560 | .ops = { | ||
| 561 | .hw_params = uda1380_pcm_hw_params, | ||
| 562 | .shutdown = uda1380_pcm_shutdown, | ||
| 563 | .prepare = uda1380_pcm_prepare, | ||
| 564 | }, | ||
| 565 | .dai_ops = { | ||
| 566 | .digital_mute = uda1380_mute, | ||
| 567 | .set_fmt = uda1380_set_dai_fmt, | ||
| 568 | }, | ||
| 569 | }, | ||
| 570 | { /* playback only - dual interface */ | ||
| 571 | .name = "UDA1380", | ||
| 572 | .playback = { | ||
| 573 | .stream_name = "Playback", | ||
| 574 | .channels_min = 1, | ||
| 575 | .channels_max = 2, | ||
| 576 | .rates = UDA1380_RATES, | ||
| 577 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 578 | }, | ||
| 579 | .ops = { | ||
| 580 | .hw_params = uda1380_pcm_hw_params, | ||
| 581 | .shutdown = uda1380_pcm_shutdown, | ||
| 582 | .prepare = uda1380_pcm_prepare, | ||
| 583 | }, | ||
| 584 | .dai_ops = { | ||
| 585 | .digital_mute = uda1380_mute, | ||
| 586 | .set_fmt = uda1380_set_dai_fmt, | ||
| 587 | }, | ||
| 588 | }, | ||
| 589 | { /* capture only - dual interface*/ | ||
| 590 | .name = "UDA1380", | ||
| 591 | .capture = { | ||
| 592 | .stream_name = "Capture", | ||
| 593 | .channels_min = 1, | ||
| 594 | .channels_max = 2, | ||
| 595 | .rates = UDA1380_RATES, | ||
| 596 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 597 | }, | ||
| 598 | .ops = { | ||
| 599 | .hw_params = uda1380_pcm_hw_params, | ||
| 600 | .shutdown = uda1380_pcm_shutdown, | ||
| 601 | .prepare = uda1380_pcm_prepare, | ||
| 602 | }, | ||
| 603 | .dai_ops = { | ||
| 604 | .set_fmt = uda1380_set_dai_fmt, | ||
| 605 | }, | ||
| 606 | }, | ||
| 607 | }; | ||
| 608 | EXPORT_SYMBOL_GPL(uda1380_dai); | ||
| 609 | |||
| 610 | static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 611 | { | ||
| 612 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 613 | struct snd_soc_codec *codec = socdev->codec; | ||
| 614 | |||
| 615 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 616 | return 0; | ||
| 617 | } | ||
| 618 | |||
| 619 | static int uda1380_resume(struct platform_device *pdev) | ||
| 620 | { | ||
| 621 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 622 | struct snd_soc_codec *codec = socdev->codec; | ||
| 623 | int i; | ||
| 624 | u8 data[2]; | ||
| 625 | u16 *cache = codec->reg_cache; | ||
| 626 | |||
| 627 | /* Sync reg_cache with the hardware */ | ||
| 628 | for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) { | ||
| 629 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
| 630 | data[1] = cache[i] & 0x00ff; | ||
| 631 | codec->hw_write(codec->control_data, data, 2); | ||
| 632 | } | ||
| 633 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 634 | uda1380_set_bias_level(codec, codec->suspend_bias_level); | ||
| 635 | return 0; | ||
| 636 | } | ||
| 637 | |||
| 638 | /* | ||
| 639 | * initialise the UDA1380 driver | ||
| 640 | * register mixer and dsp interfaces with the kernel | ||
| 641 | */ | ||
| 642 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | ||
| 643 | { | ||
| 644 | struct snd_soc_codec *codec = socdev->codec; | ||
| 645 | int ret = 0; | ||
| 646 | |||
| 647 | codec->name = "UDA1380"; | ||
| 648 | codec->owner = THIS_MODULE; | ||
| 649 | codec->read = uda1380_read_reg_cache; | ||
| 650 | codec->write = uda1380_write; | ||
| 651 | codec->set_bias_level = uda1380_set_bias_level; | ||
| 652 | codec->dai = uda1380_dai; | ||
| 653 | codec->num_dai = ARRAY_SIZE(uda1380_dai); | ||
| 654 | codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), | ||
| 655 | GFP_KERNEL); | ||
| 656 | if (codec->reg_cache == NULL) | ||
| 657 | return -ENOMEM; | ||
| 658 | codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); | ||
| 659 | codec->reg_cache_step = 1; | ||
| 660 | uda1380_reset(codec); | ||
| 661 | |||
| 662 | /* register pcms */ | ||
| 663 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
| 664 | if (ret < 0) { | ||
| 665 | pr_err("uda1380: failed to create pcms\n"); | ||
| 666 | goto pcm_err; | ||
| 667 | } | ||
| 668 | |||
| 669 | /* power on device */ | ||
| 670 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 671 | /* set clock input */ | ||
| 672 | switch (dac_clk) { | ||
| 673 | case UDA1380_DAC_CLK_SYSCLK: | ||
| 674 | uda1380_write(codec, UDA1380_CLK, 0); | ||
| 675 | break; | ||
| 676 | case UDA1380_DAC_CLK_WSPLL: | ||
| 677 | uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK); | ||
| 678 | break; | ||
| 679 | } | ||
| 680 | |||
| 681 | /* uda1380 init */ | ||
| 682 | uda1380_add_controls(codec); | ||
| 683 | uda1380_add_widgets(codec); | ||
| 684 | ret = snd_soc_register_card(socdev); | ||
| 685 | if (ret < 0) { | ||
| 686 | pr_err("uda1380: failed to register card\n"); | ||
| 687 | goto card_err; | ||
| 688 | } | ||
| 689 | |||
| 690 | return ret; | ||
| 691 | |||
| 692 | card_err: | ||
| 693 | snd_soc_free_pcms(socdev); | ||
| 694 | snd_soc_dapm_free(socdev); | ||
| 695 | pcm_err: | ||
| 696 | kfree(codec->reg_cache); | ||
| 697 | return ret; | ||
| 698 | } | ||
| 699 | |||
| 700 | static struct snd_soc_device *uda1380_socdev; | ||
| 701 | |||
| 702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 703 | |||
| 704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ | ||
| 705 | |||
| 706 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
| 707 | |||
| 708 | /* Magic definition of all other variables and things */ | ||
| 709 | I2C_CLIENT_INSMOD; | ||
| 710 | |||
| 711 | static struct i2c_driver uda1380_i2c_driver; | ||
| 712 | static struct i2c_client client_template; | ||
| 713 | |||
| 714 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
| 715 | around */ | ||
| 716 | |||
| 717 | static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
| 718 | { | ||
| 719 | struct snd_soc_device *socdev = uda1380_socdev; | ||
| 720 | struct uda1380_setup_data *setup = socdev->codec_data; | ||
| 721 | struct snd_soc_codec *codec = socdev->codec; | ||
| 722 | struct i2c_client *i2c; | ||
| 723 | int ret; | ||
| 724 | |||
| 725 | if (addr != setup->i2c_address) | ||
| 726 | return -ENODEV; | ||
| 727 | |||
| 728 | client_template.adapter = adap; | ||
| 729 | client_template.addr = addr; | ||
| 730 | |||
| 731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
| 732 | if (i2c == NULL) { | ||
| 733 | kfree(codec); | ||
| 734 | return -ENOMEM; | ||
| 735 | } | ||
| 736 | i2c_set_clientdata(i2c, codec); | ||
| 737 | codec->control_data = i2c; | ||
| 738 | |||
| 739 | ret = i2c_attach_client(i2c); | ||
| 740 | if (ret < 0) { | ||
| 741 | pr_err("uda1380: failed to attach codec at addr %x\n", addr); | ||
| 742 | goto err; | ||
| 743 | } | ||
| 744 | |||
| 745 | ret = uda1380_init(socdev, setup->dac_clk); | ||
| 746 | if (ret < 0) { | ||
| 747 | pr_err("uda1380: failed to initialise UDA1380\n"); | ||
| 748 | goto err; | ||
| 749 | } | ||
| 750 | return ret; | ||
| 751 | |||
| 752 | err: | ||
| 753 | kfree(codec); | ||
| 754 | kfree(i2c); | ||
| 755 | return ret; | ||
| 756 | } | ||
| 757 | |||
| 758 | static int uda1380_i2c_detach(struct i2c_client *client) | ||
| 759 | { | ||
| 760 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
| 761 | i2c_detach_client(client); | ||
| 762 | kfree(codec->reg_cache); | ||
| 763 | kfree(client); | ||
| 764 | return 0; | ||
| 765 | } | ||
| 766 | |||
| 767 | static int uda1380_i2c_attach(struct i2c_adapter *adap) | ||
| 768 | { | ||
| 769 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); | ||
| 770 | } | ||
| 771 | |||
| 772 | static struct i2c_driver uda1380_i2c_driver = { | ||
| 773 | .driver = { | ||
| 774 | .name = "UDA1380 I2C Codec", | ||
| 775 | .owner = THIS_MODULE, | ||
| 776 | }, | ||
| 777 | .id = I2C_DRIVERID_UDA1380, | ||
| 778 | .attach_adapter = uda1380_i2c_attach, | ||
| 779 | .detach_client = uda1380_i2c_detach, | ||
| 780 | .command = NULL, | ||
| 781 | }; | ||
| 782 | |||
| 783 | static struct i2c_client client_template = { | ||
| 784 | .name = "UDA1380", | ||
| 785 | .driver = &uda1380_i2c_driver, | ||
| 786 | }; | ||
| 787 | #endif | ||
| 788 | |||
| 789 | static int uda1380_probe(struct platform_device *pdev) | ||
| 790 | { | ||
| 791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 792 | struct uda1380_setup_data *setup; | ||
| 793 | struct snd_soc_codec *codec; | ||
| 794 | int ret = 0; | ||
| 795 | |||
| 796 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | ||
| 797 | |||
| 798 | setup = socdev->codec_data; | ||
| 799 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
| 800 | if (codec == NULL) | ||
| 801 | return -ENOMEM; | ||
| 802 | |||
| 803 | socdev->codec = codec; | ||
| 804 | mutex_init(&codec->mutex); | ||
| 805 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
| 806 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
| 807 | |||
| 808 | uda1380_socdev = socdev; | ||
| 809 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 810 | if (setup->i2c_address) { | ||
| 811 | normal_i2c[0] = setup->i2c_address; | ||
| 812 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
| 813 | ret = i2c_add_driver(&uda1380_i2c_driver); | ||
| 814 | if (ret != 0) | ||
| 815 | printk(KERN_ERR "can't add i2c driver"); | ||
| 816 | } | ||
| 817 | #else | ||
| 818 | /* Add other interfaces here */ | ||
| 819 | #endif | ||
| 820 | return ret; | ||
| 821 | } | ||
| 822 | |||
| 823 | /* power down chip */ | ||
| 824 | static int uda1380_remove(struct platform_device *pdev) | ||
| 825 | { | ||
| 826 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 827 | struct snd_soc_codec *codec = socdev->codec; | ||
| 828 | |||
| 829 | if (codec->control_data) | ||
| 830 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 831 | |||
| 832 | snd_soc_free_pcms(socdev); | ||
| 833 | snd_soc_dapm_free(socdev); | ||
| 834 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 835 | i2c_del_driver(&uda1380_i2c_driver); | ||
| 836 | #endif | ||
| 837 | kfree(codec); | ||
| 838 | |||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 842 | struct snd_soc_codec_device soc_codec_dev_uda1380 = { | ||
| 843 | .probe = uda1380_probe, | ||
| 844 | .remove = uda1380_remove, | ||
| 845 | .suspend = uda1380_suspend, | ||
| 846 | .resume = uda1380_resume, | ||
| 847 | }; | ||
| 848 | EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); | ||
| 849 | |||
| 850 | MODULE_AUTHOR("Giorgio Padrin"); | ||
| 851 | MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); | ||
| 852 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h new file mode 100644 index 000000000000..50c603e2c9f2 --- /dev/null +++ b/sound/soc/codecs/uda1380.h | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | /* | ||
| 2 | * Audio support for Philips UDA1380 | ||
| 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 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _UDA1380_H | ||
| 12 | #define _UDA1380_H | ||
| 13 | |||
| 14 | #define UDA1380_CLK 0x00 | ||
| 15 | #define UDA1380_IFACE 0x01 | ||
| 16 | #define UDA1380_PM 0x02 | ||
| 17 | #define UDA1380_AMIX 0x03 | ||
| 18 | #define UDA1380_HP 0x04 | ||
| 19 | #define UDA1380_MVOL 0x10 | ||
| 20 | #define UDA1380_MIXVOL 0x11 | ||
| 21 | #define UDA1380_MODE 0x12 | ||
| 22 | #define UDA1380_DEEMP 0x13 | ||
| 23 | #define UDA1380_MIXER 0x14 | ||
| 24 | #define UDA1380_INTSTAT 0x18 | ||
| 25 | #define UDA1380_DEC 0x20 | ||
| 26 | #define UDA1380_PGA 0x21 | ||
| 27 | #define UDA1380_ADC 0x22 | ||
| 28 | #define UDA1380_AGC 0x23 | ||
| 29 | #define UDA1380_DECSTAT 0x28 | ||
| 30 | #define UDA1380_RESET 0x7f | ||
| 31 | |||
| 32 | #define UDA1380_CACHEREGNUM 0x24 | ||
| 33 | |||
| 34 | /* Register flags */ | ||
| 35 | #define R00_EN_ADC 0x0800 | ||
| 36 | #define R00_EN_DEC 0x0400 | ||
| 37 | #define R00_EN_DAC 0x0200 | ||
| 38 | #define R00_EN_INT 0x0100 | ||
| 39 | #define R00_DAC_CLK 0x0010 | ||
| 40 | #define R01_SFORI_I2S 0x0000 | ||
| 41 | #define R01_SFORI_LSB16 0x0100 | ||
| 42 | #define R01_SFORI_LSB18 0x0200 | ||
| 43 | #define R01_SFORI_LSB20 0x0300 | ||
| 44 | #define R01_SFORI_MSB 0x0500 | ||
| 45 | #define R01_SFORI_MASK 0x0700 | ||
| 46 | #define R01_SFORO_I2S 0x0000 | ||
| 47 | #define R01_SFORO_LSB16 0x0001 | ||
| 48 | #define R01_SFORO_LSB18 0x0002 | ||
| 49 | #define R01_SFORO_LSB20 0x0003 | ||
| 50 | #define R01_SFORO_LSB24 0x0004 | ||
| 51 | #define R01_SFORO_MSB 0x0005 | ||
| 52 | #define R01_SFORO_MASK 0x0007 | ||
| 53 | #define R01_SEL_SOURCE 0x0040 | ||
| 54 | #define R01_SIM 0x0010 | ||
| 55 | #define R02_PON_PLL 0x8000 | ||
| 56 | #define R02_PON_HP 0x2000 | ||
| 57 | #define R02_PON_DAC 0x0400 | ||
| 58 | #define R02_PON_BIAS 0x0100 | ||
| 59 | #define R02_EN_AVC 0x0080 | ||
| 60 | #define R02_PON_AVC 0x0040 | ||
| 61 | #define R02_PON_LNA 0x0010 | ||
| 62 | #define R02_PON_PGAL 0x0008 | ||
| 63 | #define R02_PON_ADCL 0x0004 | ||
| 64 | #define R02_PON_PGAR 0x0002 | ||
| 65 | #define R02_PON_ADCR 0x0001 | ||
| 66 | #define R13_MTM 0x4000 | ||
| 67 | #define R14_SILENCE 0x0080 | ||
| 68 | #define R14_SDET_ON 0x0040 | ||
| 69 | #define R21_MT_ADC 0x8000 | ||
| 70 | #define R22_SEL_LNA 0x0008 | ||
| 71 | #define R22_SEL_MIC 0x0004 | ||
| 72 | #define R22_SKIP_DCFIL 0x0002 | ||
| 73 | #define R23_AGC_EN 0x0001 | ||
| 74 | |||
| 75 | struct uda1380_setup_data { | ||
| 76 | unsigned short i2c_address; | ||
| 77 | int dac_clk; | ||
| 78 | #define UDA1380_DAC_CLK_SYSCLK 0 | ||
| 79 | #define UDA1380_DAC_CLK_WSPLL 1 | ||
| 80 | }; | ||
| 81 | |||
| 82 | #define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ | ||
| 83 | #define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ | ||
| 84 | #define UDA1380_DAI_CAPTURE 2 /* capture DAI */ | ||
| 85 | |||
| 86 | extern struct snd_soc_dai uda1380_dai[3]; | ||
| 87 | extern struct snd_soc_codec_device soc_codec_dev_uda1380; | ||
| 88 | |||
| 89 | #endif /* _UDA1380_H */ | ||
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c new file mode 100644 index 000000000000..67325fd95447 --- /dev/null +++ b/sound/soc/codecs/wm8510.c | |||
| @@ -0,0 +1,817 @@ | |||
| 1 | /* | ||
| 2 | * wm8510.c -- WM8510 ALSA Soc Audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2006 Wolfson Microelectronics PLC. | ||
| 5 | * | ||
| 6 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/moduleparam.h> | ||
| 15 | #include <linux/kernel.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 <sound/core.h> | ||
| 22 | #include <sound/pcm.h> | ||
| 23 | #include <sound/pcm_params.h> | ||
| 24 | #include <sound/soc.h> | ||
| 25 | #include <sound/soc-dapm.h> | ||
| 26 | #include <sound/initval.h> | ||
| 27 | |||
| 28 | #include "wm8510.h" | ||
| 29 | |||
| 30 | #define AUDIO_NAME "wm8510" | ||
| 31 | #define WM8510_VERSION "0.6" | ||
| 32 | |||
| 33 | struct snd_soc_codec_device soc_codec_dev_wm8510; | ||
| 34 | |||
| 35 | /* | ||
| 36 | * wm8510 register cache | ||
| 37 | * We can't read the WM8510 register space when we are | ||
| 38 | * using 2 wire for device control, so we cache them instead. | ||
| 39 | */ | ||
| 40 | static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | ||
| 41 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 42 | 0x0050, 0x0000, 0x0140, 0x0000, | ||
| 43 | 0x0000, 0x0000, 0x0000, 0x00ff, | ||
| 44 | 0x0000, 0x0000, 0x0100, 0x00ff, | ||
| 45 | 0x0000, 0x0000, 0x012c, 0x002c, | ||
| 46 | 0x002c, 0x002c, 0x002c, 0x0000, | ||
| 47 | 0x0032, 0x0000, 0x0000, 0x0000, | ||
| 48 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 49 | 0x0038, 0x000b, 0x0032, 0x0000, | ||
| 50 | 0x0008, 0x000c, 0x0093, 0x00e9, | ||
| 51 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 52 | 0x0003, 0x0010, 0x0000, 0x0000, | ||
| 53 | 0x0000, 0x0002, 0x0001, 0x0000, | ||
| 54 | 0x0000, 0x0000, 0x0039, 0x0000, | ||
| 55 | 0x0001, | ||
| 56 | }; | ||
| 57 | |||
| 58 | /* | ||
| 59 | * read wm8510 register cache | ||
| 60 | */ | ||
| 61 | static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, | ||
| 62 | unsigned int reg) | ||
| 63 | { | ||
| 64 | u16 *cache = codec->reg_cache; | ||
| 65 | if (reg == WM8510_RESET) | ||
| 66 | return 0; | ||
| 67 | if (reg >= WM8510_CACHEREGNUM) | ||
| 68 | return -1; | ||
| 69 | return cache[reg]; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* | ||
| 73 | * write wm8510 register cache | ||
| 74 | */ | ||
| 75 | static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, | ||
| 76 | u16 reg, unsigned int value) | ||
| 77 | { | ||
| 78 | u16 *cache = codec->reg_cache; | ||
| 79 | if (reg >= WM8510_CACHEREGNUM) | ||
| 80 | return; | ||
| 81 | cache[reg] = value; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* | ||
| 85 | * write to the WM8510 register space | ||
| 86 | */ | ||
| 87 | static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, | ||
| 88 | unsigned int value) | ||
| 89 | { | ||
| 90 | u8 data[2]; | ||
| 91 | |||
| 92 | /* data is | ||
| 93 | * D15..D9 WM8510 register offset | ||
| 94 | * D8...D0 register data | ||
| 95 | */ | ||
| 96 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
| 97 | data[1] = value & 0x00ff; | ||
| 98 | |||
| 99 | wm8510_write_reg_cache(codec, reg, value); | ||
| 100 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
| 101 | return 0; | ||
| 102 | else | ||
| 103 | return -EIO; | ||
| 104 | } | ||
| 105 | |||
| 106 | #define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) | ||
| 107 | |||
| 108 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; | ||
| 109 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | ||
| 110 | static const char *wm8510_alc[] = { "ALC", "Limiter" }; | ||
| 111 | |||
| 112 | static const struct soc_enum wm8510_enum[] = { | ||
| 113 | SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */ | ||
| 114 | SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */ | ||
| 115 | SOC_ENUM_SINGLE(WM8510_DAC, 4, 4, wm8510_deemp), | ||
| 116 | SOC_ENUM_SINGLE(WM8510_ALC3, 8, 2, wm8510_alc), | ||
| 117 | }; | ||
| 118 | |||
| 119 | static const struct snd_kcontrol_new wm8510_snd_controls[] = { | ||
| 120 | |||
| 121 | SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0), | ||
| 122 | |||
| 123 | SOC_ENUM("DAC Companding", wm8510_enum[1]), | ||
| 124 | SOC_ENUM("ADC Companding", wm8510_enum[0]), | ||
| 125 | |||
| 126 | SOC_ENUM("Playback De-emphasis", wm8510_enum[2]), | ||
| 127 | SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0), | ||
| 128 | |||
| 129 | SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0), | ||
| 130 | |||
| 131 | SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0), | ||
| 132 | SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0), | ||
| 133 | SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0), | ||
| 134 | |||
| 135 | SOC_SINGLE("Capture Volume", WM8510_ADCVOL, 0, 127, 0), | ||
| 136 | |||
| 137 | SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1, 8, 1, 0), | ||
| 138 | SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1, 4, 15, 0), | ||
| 139 | SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1, 0, 15, 0), | ||
| 140 | |||
| 141 | SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2, 4, 7, 0), | ||
| 142 | SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2, 0, 15, 0), | ||
| 143 | |||
| 144 | SOC_SINGLE("ALC Enable Switch", WM8510_ALC1, 8, 1, 0), | ||
| 145 | SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1, 3, 7, 0), | ||
| 146 | SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1, 0, 7, 0), | ||
| 147 | |||
| 148 | SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2, 8, 1, 0), | ||
| 149 | SOC_SINGLE("ALC Capture Hold", WM8510_ALC2, 4, 7, 0), | ||
| 150 | SOC_SINGLE("ALC Capture Target", WM8510_ALC2, 0, 15, 0), | ||
| 151 | |||
| 152 | SOC_ENUM("ALC Capture Mode", wm8510_enum[3]), | ||
| 153 | SOC_SINGLE("ALC Capture Decay", WM8510_ALC3, 4, 15, 0), | ||
| 154 | SOC_SINGLE("ALC Capture Attack", WM8510_ALC3, 0, 15, 0), | ||
| 155 | |||
| 156 | SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE, 3, 1, 0), | ||
| 157 | SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE, 0, 7, 0), | ||
| 158 | |||
| 159 | SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA, 7, 1, 0), | ||
| 160 | SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA, 0, 63, 0), | ||
| 161 | |||
| 162 | SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL, 7, 1, 0), | ||
| 163 | SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL, 6, 1, 1), | ||
| 164 | SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL, 0, 63, 0), | ||
| 165 | SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0), | ||
| 166 | |||
| 167 | SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), | ||
| 168 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), | ||
| 169 | }; | ||
| 170 | |||
| 171 | /* add non dapm controls */ | ||
| 172 | static int wm8510_add_controls(struct snd_soc_codec *codec) | ||
| 173 | { | ||
| 174 | int err, i; | ||
| 175 | |||
| 176 | for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { | ||
| 177 | err = snd_ctl_add(codec->card, | ||
| 178 | snd_soc_cnew(&wm8510_snd_controls[i], codec, | ||
| 179 | NULL)); | ||
| 180 | if (err < 0) | ||
| 181 | return err; | ||
| 182 | } | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | /* Speaker Output Mixer */ | ||
| 188 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { | ||
| 189 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), | ||
| 190 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0), | ||
| 191 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0), | ||
| 192 | }; | ||
| 193 | |||
| 194 | /* Mono Output Mixer */ | ||
| 195 | static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = { | ||
| 196 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0), | ||
| 197 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0), | ||
| 198 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), | ||
| 199 | }; | ||
| 200 | |||
| 201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { | ||
| 202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), | ||
| 203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), | ||
| 204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), | ||
| 205 | }; | ||
| 206 | |||
| 207 | static const struct snd_kcontrol_new wm8510_micpga_controls[] = { | ||
| 208 | SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0), | ||
| 209 | SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0), | ||
| 210 | SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0), | ||
| 211 | }; | ||
| 212 | |||
| 213 | static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = { | ||
| 214 | SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0, | ||
| 215 | &wm8510_speaker_mixer_controls[0], | ||
| 216 | ARRAY_SIZE(wm8510_speaker_mixer_controls)), | ||
| 217 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0, | ||
| 218 | &wm8510_mono_mixer_controls[0], | ||
| 219 | ARRAY_SIZE(wm8510_mono_mixer_controls)), | ||
| 220 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0), | ||
| 221 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0), | ||
| 222 | SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0), | ||
| 223 | SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0), | ||
| 224 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), | ||
| 225 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), | ||
| 226 | |||
| 227 | SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, | ||
| 228 | &wm8510_micpga_controls[0], | ||
| 229 | ARRAY_SIZE(wm8510_micpga_controls)), | ||
| 230 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, | ||
| 231 | &wm8510_boost_controls[0], | ||
| 232 | ARRAY_SIZE(wm8510_boost_controls)), | ||
| 233 | |||
| 234 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0), | ||
| 235 | |||
| 236 | SND_SOC_DAPM_INPUT("MICN"), | ||
| 237 | SND_SOC_DAPM_INPUT("MICP"), | ||
| 238 | SND_SOC_DAPM_INPUT("AUX"), | ||
| 239 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | ||
| 240 | SND_SOC_DAPM_OUTPUT("SPKOUTP"), | ||
| 241 | SND_SOC_DAPM_OUTPUT("SPKOUTN"), | ||
| 242 | }; | ||
| 243 | |||
| 244 | static const struct snd_soc_dapm_route audio_map[] = { | ||
| 245 | /* Mono output mixer */ | ||
| 246 | {"Mono Mixer", "PCM Playback Switch", "DAC"}, | ||
| 247 | {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, | ||
| 248 | {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, | ||
| 249 | |||
| 250 | /* Speaker output mixer */ | ||
| 251 | {"Speaker Mixer", "PCM Playback Switch", "DAC"}, | ||
| 252 | {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, | ||
| 253 | {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, | ||
| 254 | |||
| 255 | /* Outputs */ | ||
| 256 | {"Mono Out", NULL, "Mono Mixer"}, | ||
| 257 | {"MONOOUT", NULL, "Mono Out"}, | ||
| 258 | {"SpkN Out", NULL, "Speaker Mixer"}, | ||
| 259 | {"SpkP Out", NULL, "Speaker Mixer"}, | ||
| 260 | {"SPKOUTN", NULL, "SpkN Out"}, | ||
| 261 | {"SPKOUTP", NULL, "SpkP Out"}, | ||
| 262 | |||
| 263 | /* Microphone PGA */ | ||
| 264 | {"Mic PGA", "MICN Switch", "MICN"}, | ||
| 265 | {"Mic PGA", "MICP Switch", "MICP"}, | ||
| 266 | { "Mic PGA", "AUX Switch", "Aux Input" }, | ||
| 267 | |||
| 268 | /* Boost Mixer */ | ||
| 269 | {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, | ||
| 270 | {"Boost Mixer", "Mic Volume", "MICP"}, | ||
| 271 | {"Boost Mixer", "Aux Volume", "Aux Input"}, | ||
| 272 | |||
| 273 | {"ADC", NULL, "Boost Mixer"}, | ||
| 274 | }; | ||
| 275 | |||
| 276 | static int wm8510_add_widgets(struct snd_soc_codec *codec) | ||
| 277 | { | ||
| 278 | snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets, | ||
| 279 | ARRAY_SIZE(wm8510_dapm_widgets)); | ||
| 280 | |||
| 281 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
| 282 | |||
| 283 | snd_soc_dapm_new_widgets(codec); | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | struct pll_ { | ||
| 288 | unsigned int pre_div:4; /* prescale - 1 */ | ||
| 289 | unsigned int n:4; | ||
| 290 | unsigned int k; | ||
| 291 | }; | ||
| 292 | |||
| 293 | static struct pll_ pll_div; | ||
| 294 | |||
| 295 | /* The size in bits of the pll divide multiplied by 10 | ||
| 296 | * to allow rounding later */ | ||
| 297 | #define FIXED_PLL_SIZE ((1 << 24) * 10) | ||
| 298 | |||
| 299 | static void pll_factors(unsigned int target, unsigned int source) | ||
| 300 | { | ||
| 301 | unsigned long long Kpart; | ||
| 302 | unsigned int K, Ndiv, Nmod; | ||
| 303 | |||
| 304 | Ndiv = target / source; | ||
| 305 | if (Ndiv < 6) { | ||
| 306 | source >>= 1; | ||
| 307 | pll_div.pre_div = 1; | ||
| 308 | Ndiv = target / source; | ||
| 309 | } else | ||
| 310 | pll_div.pre_div = 0; | ||
| 311 | |||
| 312 | if ((Ndiv < 6) || (Ndiv > 12)) | ||
| 313 | printk(KERN_WARNING | ||
| 314 | "WM8510 N value %d outwith recommended range!d\n", | ||
| 315 | Ndiv); | ||
| 316 | |||
| 317 | pll_div.n = Ndiv; | ||
| 318 | Nmod = target % source; | ||
| 319 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
| 320 | |||
| 321 | do_div(Kpart, source); | ||
| 322 | |||
| 323 | K = Kpart & 0xFFFFFFFF; | ||
| 324 | |||
| 325 | /* Check if we need to round */ | ||
| 326 | if ((K % 10) >= 5) | ||
| 327 | K += 5; | ||
| 328 | |||
| 329 | /* Move down to proper range now rounding is done */ | ||
| 330 | K /= 10; | ||
| 331 | |||
| 332 | pll_div.k = K; | ||
| 333 | } | ||
| 334 | |||
| 335 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
| 336 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
| 337 | { | ||
| 338 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 339 | u16 reg; | ||
| 340 | |||
| 341 | if (freq_in == 0 || freq_out == 0) { | ||
| 342 | /* Clock CODEC directly from MCLK */ | ||
| 343 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | ||
| 344 | wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); | ||
| 345 | |||
| 346 | /* Turn off PLL */ | ||
| 347 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | ||
| 348 | wm8510_write(codec, WM8510_POWER1, reg & 0x1df); | ||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | pll_factors(freq_out*8, freq_in); | ||
| 353 | |||
| 354 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); | ||
| 355 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); | ||
| 356 | wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); | ||
| 357 | wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); | ||
| 358 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | ||
| 359 | wm8510_write(codec, WM8510_POWER1, reg | 0x020); | ||
| 360 | |||
| 361 | /* Run CODEC from PLL instead of MCLK */ | ||
| 362 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | ||
| 363 | wm8510_write(codec, WM8510_CLOCK, reg | 0x100); | ||
| 364 | |||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | /* | ||
| 369 | * Configure WM8510 clock dividers. | ||
| 370 | */ | ||
| 371 | static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
| 372 | int div_id, int div) | ||
| 373 | { | ||
| 374 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 375 | u16 reg; | ||
| 376 | |||
| 377 | switch (div_id) { | ||
| 378 | case WM8510_OPCLKDIV: | ||
| 379 | reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; | ||
| 380 | wm8510_write(codec, WM8510_GPIO, reg | div); | ||
| 381 | break; | ||
| 382 | case WM8510_MCLKDIV: | ||
| 383 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; | ||
| 384 | wm8510_write(codec, WM8510_CLOCK, reg | div); | ||
| 385 | break; | ||
| 386 | case WM8510_ADCCLK: | ||
| 387 | reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; | ||
| 388 | wm8510_write(codec, WM8510_ADC, reg | div); | ||
| 389 | break; | ||
| 390 | case WM8510_DACCLK: | ||
| 391 | reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; | ||
| 392 | wm8510_write(codec, WM8510_DAC, reg | div); | ||
| 393 | break; | ||
| 394 | case WM8510_BCLKDIV: | ||
| 395 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; | ||
| 396 | wm8510_write(codec, WM8510_CLOCK, reg | div); | ||
| 397 | break; | ||
| 398 | default: | ||
| 399 | return -EINVAL; | ||
| 400 | } | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
| 406 | unsigned int fmt) | ||
| 407 | { | ||
| 408 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 409 | u16 iface = 0; | ||
| 410 | u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; | ||
| 411 | |||
| 412 | /* set master/slave audio interface */ | ||
| 413 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 414 | case SND_SOC_DAIFMT_CBM_CFM: | ||
| 415 | clk |= 0x0001; | ||
| 416 | break; | ||
| 417 | case SND_SOC_DAIFMT_CBS_CFS: | ||
| 418 | break; | ||
| 419 | default: | ||
| 420 | return -EINVAL; | ||
| 421 | } | ||
| 422 | |||
| 423 | /* interface format */ | ||
| 424 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 425 | case SND_SOC_DAIFMT_I2S: | ||
| 426 | iface |= 0x0010; | ||
| 427 | break; | ||
| 428 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 429 | break; | ||
| 430 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 431 | iface |= 0x0008; | ||
| 432 | break; | ||
| 433 | case SND_SOC_DAIFMT_DSP_A: | ||
| 434 | iface |= 0x00018; | ||
| 435 | break; | ||
| 436 | default: | ||
| 437 | return -EINVAL; | ||
| 438 | } | ||
| 439 | |||
| 440 | /* clock inversion */ | ||
| 441 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
| 442 | case SND_SOC_DAIFMT_NB_NF: | ||
| 443 | break; | ||
| 444 | case SND_SOC_DAIFMT_IB_IF: | ||
| 445 | iface |= 0x0180; | ||
| 446 | break; | ||
| 447 | case SND_SOC_DAIFMT_IB_NF: | ||
| 448 | iface |= 0x0100; | ||
| 449 | break; | ||
| 450 | case SND_SOC_DAIFMT_NB_IF: | ||
| 451 | iface |= 0x0080; | ||
| 452 | break; | ||
| 453 | default: | ||
| 454 | return -EINVAL; | ||
| 455 | } | ||
| 456 | |||
| 457 | wm8510_write(codec, WM8510_IFACE, iface); | ||
| 458 | wm8510_write(codec, WM8510_CLOCK, clk); | ||
| 459 | return 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 463 | struct snd_pcm_hw_params *params) | ||
| 464 | { | ||
| 465 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 466 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 467 | struct snd_soc_codec *codec = socdev->codec; | ||
| 468 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; | ||
| 469 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; | ||
| 470 | |||
| 471 | /* bit size */ | ||
| 472 | switch (params_format(params)) { | ||
| 473 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 474 | break; | ||
| 475 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
| 476 | iface |= 0x0020; | ||
| 477 | break; | ||
| 478 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 479 | iface |= 0x0040; | ||
| 480 | break; | ||
| 481 | case SNDRV_PCM_FORMAT_S32_LE: | ||
| 482 | iface |= 0x0060; | ||
| 483 | break; | ||
| 484 | } | ||
| 485 | |||
| 486 | /* filter coefficient */ | ||
| 487 | switch (params_rate(params)) { | ||
| 488 | case SNDRV_PCM_RATE_8000: | ||
| 489 | adn |= 0x5 << 1; | ||
| 490 | break; | ||
| 491 | case SNDRV_PCM_RATE_11025: | ||
| 492 | adn |= 0x4 << 1; | ||
| 493 | break; | ||
| 494 | case SNDRV_PCM_RATE_16000: | ||
| 495 | adn |= 0x3 << 1; | ||
| 496 | break; | ||
| 497 | case SNDRV_PCM_RATE_22050: | ||
| 498 | adn |= 0x2 << 1; | ||
| 499 | break; | ||
| 500 | case SNDRV_PCM_RATE_32000: | ||
| 501 | adn |= 0x1 << 1; | ||
| 502 | break; | ||
| 503 | case SNDRV_PCM_RATE_44100: | ||
| 504 | case SNDRV_PCM_RATE_48000: | ||
| 505 | break; | ||
| 506 | } | ||
| 507 | |||
| 508 | wm8510_write(codec, WM8510_IFACE, iface); | ||
| 509 | wm8510_write(codec, WM8510_ADD, adn); | ||
| 510 | return 0; | ||
| 511 | } | ||
| 512 | |||
| 513 | static int wm8510_mute(struct snd_soc_dai *dai, int mute) | ||
| 514 | { | ||
| 515 | struct snd_soc_codec *codec = dai->codec; | ||
| 516 | u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; | ||
| 517 | |||
| 518 | if (mute) | ||
| 519 | wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); | ||
| 520 | else | ||
| 521 | wm8510_write(codec, WM8510_DAC, mute_reg); | ||
| 522 | return 0; | ||
| 523 | } | ||
| 524 | |||
| 525 | /* liam need to make this lower power with dapm */ | ||
| 526 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, | ||
| 527 | enum snd_soc_bias_level level) | ||
| 528 | { | ||
| 529 | |||
| 530 | switch (level) { | ||
| 531 | case SND_SOC_BIAS_ON: | ||
| 532 | wm8510_write(codec, WM8510_POWER1, 0x1ff); | ||
| 533 | wm8510_write(codec, WM8510_POWER2, 0x1ff); | ||
| 534 | wm8510_write(codec, WM8510_POWER3, 0x1ff); | ||
| 535 | break; | ||
| 536 | case SND_SOC_BIAS_PREPARE: | ||
| 537 | case SND_SOC_BIAS_STANDBY: | ||
| 538 | break; | ||
| 539 | case SND_SOC_BIAS_OFF: | ||
| 540 | /* everything off, dac mute, inactive */ | ||
| 541 | wm8510_write(codec, WM8510_POWER1, 0x0); | ||
| 542 | wm8510_write(codec, WM8510_POWER2, 0x0); | ||
| 543 | wm8510_write(codec, WM8510_POWER3, 0x0); | ||
| 544 | break; | ||
| 545 | } | ||
| 546 | codec->bias_level = level; | ||
| 547 | return 0; | ||
| 548 | } | ||
| 549 | |||
| 550 | #define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
| 551 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
| 552 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
| 553 | |||
| 554 | #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
| 555 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
| 556 | |||
| 557 | struct snd_soc_dai wm8510_dai = { | ||
| 558 | .name = "WM8510 HiFi", | ||
| 559 | .playback = { | ||
| 560 | .stream_name = "Playback", | ||
| 561 | .channels_min = 2, | ||
| 562 | .channels_max = 2, | ||
| 563 | .rates = WM8510_RATES, | ||
| 564 | .formats = WM8510_FORMATS,}, | ||
| 565 | .capture = { | ||
| 566 | .stream_name = "Capture", | ||
| 567 | .channels_min = 2, | ||
| 568 | .channels_max = 2, | ||
| 569 | .rates = WM8510_RATES, | ||
| 570 | .formats = WM8510_FORMATS,}, | ||
| 571 | .ops = { | ||
| 572 | .hw_params = wm8510_pcm_hw_params, | ||
| 573 | }, | ||
| 574 | .dai_ops = { | ||
| 575 | .digital_mute = wm8510_mute, | ||
| 576 | .set_fmt = wm8510_set_dai_fmt, | ||
| 577 | .set_clkdiv = wm8510_set_dai_clkdiv, | ||
| 578 | .set_pll = wm8510_set_dai_pll, | ||
| 579 | }, | ||
| 580 | }; | ||
| 581 | EXPORT_SYMBOL_GPL(wm8510_dai); | ||
| 582 | |||
| 583 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 584 | { | ||
| 585 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 586 | struct snd_soc_codec *codec = socdev->codec; | ||
| 587 | |||
| 588 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 592 | static int wm8510_resume(struct platform_device *pdev) | ||
| 593 | { | ||
| 594 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 595 | struct snd_soc_codec *codec = socdev->codec; | ||
| 596 | int i; | ||
| 597 | u8 data[2]; | ||
| 598 | u16 *cache = codec->reg_cache; | ||
| 599 | |||
| 600 | /* Sync reg_cache with the hardware */ | ||
| 601 | for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) { | ||
| 602 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
| 603 | data[1] = cache[i] & 0x00ff; | ||
| 604 | codec->hw_write(codec->control_data, data, 2); | ||
| 605 | } | ||
| 606 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 607 | wm8510_set_bias_level(codec, codec->suspend_bias_level); | ||
| 608 | return 0; | ||
| 609 | } | ||
| 610 | |||
| 611 | /* | ||
| 612 | * initialise the WM8510 driver | ||
| 613 | * register the mixer and dsp interfaces with the kernel | ||
| 614 | */ | ||
| 615 | static int wm8510_init(struct snd_soc_device *socdev) | ||
| 616 | { | ||
| 617 | struct snd_soc_codec *codec = socdev->codec; | ||
| 618 | int ret = 0; | ||
| 619 | |||
| 620 | codec->name = "WM8510"; | ||
| 621 | codec->owner = THIS_MODULE; | ||
| 622 | codec->read = wm8510_read_reg_cache; | ||
| 623 | codec->write = wm8510_write; | ||
| 624 | codec->set_bias_level = wm8510_set_bias_level; | ||
| 625 | codec->dai = &wm8510_dai; | ||
| 626 | codec->num_dai = 1; | ||
| 627 | codec->reg_cache_size = ARRAY_SIZE(wm8510_reg); | ||
| 628 | codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL); | ||
| 629 | |||
| 630 | if (codec->reg_cache == NULL) | ||
| 631 | return -ENOMEM; | ||
| 632 | |||
| 633 | wm8510_reset(codec); | ||
| 634 | |||
| 635 | /* register pcms */ | ||
| 636 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
| 637 | if (ret < 0) { | ||
| 638 | printk(KERN_ERR "wm8510: failed to create pcms\n"); | ||
| 639 | goto pcm_err; | ||
| 640 | } | ||
| 641 | |||
| 642 | /* power on device */ | ||
| 643 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 644 | wm8510_add_controls(codec); | ||
| 645 | wm8510_add_widgets(codec); | ||
| 646 | ret = snd_soc_register_card(socdev); | ||
| 647 | if (ret < 0) { | ||
| 648 | printk(KERN_ERR "wm8510: failed to register card\n"); | ||
| 649 | goto card_err; | ||
| 650 | } | ||
| 651 | return ret; | ||
| 652 | |||
| 653 | card_err: | ||
| 654 | snd_soc_free_pcms(socdev); | ||
| 655 | snd_soc_dapm_free(socdev); | ||
| 656 | pcm_err: | ||
| 657 | kfree(codec->reg_cache); | ||
| 658 | return ret; | ||
| 659 | } | ||
| 660 | |||
| 661 | static struct snd_soc_device *wm8510_socdev; | ||
| 662 | |||
| 663 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 664 | |||
| 665 | /* | ||
| 666 | * WM8510 2 wire address is 0x1a | ||
| 667 | */ | ||
| 668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ | ||
| 669 | |||
| 670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
| 671 | |||
| 672 | /* Magic definition of all other variables and things */ | ||
| 673 | I2C_CLIENT_INSMOD; | ||
| 674 | |||
| 675 | static struct i2c_driver wm8510_i2c_driver; | ||
| 676 | static struct i2c_client client_template; | ||
| 677 | |||
| 678 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
| 679 | around */ | ||
| 680 | |||
| 681 | static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
| 682 | { | ||
| 683 | struct snd_soc_device *socdev = wm8510_socdev; | ||
| 684 | struct wm8510_setup_data *setup = socdev->codec_data; | ||
| 685 | struct snd_soc_codec *codec = socdev->codec; | ||
| 686 | struct i2c_client *i2c; | ||
| 687 | int ret; | ||
| 688 | |||
| 689 | if (addr != setup->i2c_address) | ||
| 690 | return -ENODEV; | ||
| 691 | |||
| 692 | client_template.adapter = adap; | ||
| 693 | client_template.addr = addr; | ||
| 694 | |||
| 695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
| 696 | if (i2c == NULL) { | ||
| 697 | kfree(codec); | ||
| 698 | return -ENOMEM; | ||
| 699 | } | ||
| 700 | i2c_set_clientdata(i2c, codec); | ||
| 701 | codec->control_data = i2c; | ||
| 702 | |||
| 703 | ret = i2c_attach_client(i2c); | ||
| 704 | if (ret < 0) { | ||
| 705 | pr_err("failed to attach codec at addr %x\n", addr); | ||
| 706 | goto err; | ||
| 707 | } | ||
| 708 | |||
| 709 | ret = wm8510_init(socdev); | ||
| 710 | if (ret < 0) { | ||
| 711 | pr_err("failed to initialise WM8510\n"); | ||
| 712 | goto err; | ||
| 713 | } | ||
| 714 | return ret; | ||
| 715 | |||
| 716 | err: | ||
| 717 | kfree(codec); | ||
| 718 | kfree(i2c); | ||
| 719 | return ret; | ||
| 720 | } | ||
| 721 | |||
| 722 | static int wm8510_i2c_detach(struct i2c_client *client) | ||
| 723 | { | ||
| 724 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
| 725 | i2c_detach_client(client); | ||
| 726 | kfree(codec->reg_cache); | ||
| 727 | kfree(client); | ||
| 728 | return 0; | ||
| 729 | } | ||
| 730 | |||
| 731 | static int wm8510_i2c_attach(struct i2c_adapter *adap) | ||
| 732 | { | ||
| 733 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); | ||
| 734 | } | ||
| 735 | |||
| 736 | /* corgi i2c codec control layer */ | ||
| 737 | static struct i2c_driver wm8510_i2c_driver = { | ||
| 738 | .driver = { | ||
| 739 | .name = "WM8510 I2C Codec", | ||
| 740 | .owner = THIS_MODULE, | ||
| 741 | }, | ||
| 742 | .id = I2C_DRIVERID_WM8510, | ||
| 743 | .attach_adapter = wm8510_i2c_attach, | ||
| 744 | .detach_client = wm8510_i2c_detach, | ||
| 745 | .command = NULL, | ||
| 746 | }; | ||
| 747 | |||
| 748 | static struct i2c_client client_template = { | ||
| 749 | .name = "WM8510", | ||
| 750 | .driver = &wm8510_i2c_driver, | ||
| 751 | }; | ||
| 752 | #endif | ||
| 753 | |||
| 754 | static int wm8510_probe(struct platform_device *pdev) | ||
| 755 | { | ||
| 756 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 757 | struct wm8510_setup_data *setup; | ||
| 758 | struct snd_soc_codec *codec; | ||
| 759 | int ret = 0; | ||
| 760 | |||
| 761 | pr_info("WM8510 Audio Codec %s", WM8510_VERSION); | ||
| 762 | |||
| 763 | setup = socdev->codec_data; | ||
| 764 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
| 765 | if (codec == NULL) | ||
| 766 | return -ENOMEM; | ||
| 767 | |||
| 768 | socdev->codec = codec; | ||
| 769 | mutex_init(&codec->mutex); | ||
| 770 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
| 771 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
| 772 | |||
| 773 | wm8510_socdev = socdev; | ||
| 774 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 775 | if (setup->i2c_address) { | ||
| 776 | normal_i2c[0] = setup->i2c_address; | ||
| 777 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
| 778 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
| 779 | if (ret != 0) | ||
| 780 | printk(KERN_ERR "can't add i2c driver"); | ||
| 781 | } | ||
| 782 | #else | ||
| 783 | /* Add other interfaces here */ | ||
| 784 | #endif | ||
| 785 | return ret; | ||
| 786 | } | ||
| 787 | |||
| 788 | /* power down chip */ | ||
| 789 | static int wm8510_remove(struct platform_device *pdev) | ||
| 790 | { | ||
| 791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 792 | struct snd_soc_codec *codec = socdev->codec; | ||
| 793 | |||
| 794 | if (codec->control_data) | ||
| 795 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 796 | |||
| 797 | snd_soc_free_pcms(socdev); | ||
| 798 | snd_soc_dapm_free(socdev); | ||
| 799 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 800 | i2c_del_driver(&wm8510_i2c_driver); | ||
| 801 | #endif | ||
| 802 | kfree(codec); | ||
| 803 | |||
| 804 | return 0; | ||
| 805 | } | ||
| 806 | |||
| 807 | struct snd_soc_codec_device soc_codec_dev_wm8510 = { | ||
| 808 | .probe = wm8510_probe, | ||
| 809 | .remove = wm8510_remove, | ||
| 810 | .suspend = wm8510_suspend, | ||
| 811 | .resume = wm8510_resume, | ||
| 812 | }; | ||
| 813 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); | ||
| 814 | |||
| 815 | MODULE_DESCRIPTION("ASoC WM8510 driver"); | ||
| 816 | MODULE_AUTHOR("Liam Girdwood"); | ||
| 817 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h new file mode 100644 index 000000000000..f5d2e42eb3f4 --- /dev/null +++ b/sound/soc/codecs/wm8510.h | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | /* | ||
| 2 | * wm8510.h -- WM8510 Soc Audio driver | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef _WM8510_H | ||
| 10 | #define _WM8510_H | ||
| 11 | |||
| 12 | /* WM8510 register space */ | ||
| 13 | |||
| 14 | #define WM8510_RESET 0x0 | ||
| 15 | #define WM8510_POWER1 0x1 | ||
| 16 | #define WM8510_POWER2 0x2 | ||
| 17 | #define WM8510_POWER3 0x3 | ||
| 18 | #define WM8510_IFACE 0x4 | ||
| 19 | #define WM8510_COMP 0x5 | ||
| 20 | #define WM8510_CLOCK 0x6 | ||
| 21 | #define WM8510_ADD 0x7 | ||
| 22 | #define WM8510_GPIO 0x8 | ||
| 23 | #define WM8510_DAC 0xa | ||
| 24 | #define WM8510_DACVOL 0xb | ||
| 25 | #define WM8510_ADC 0xe | ||
| 26 | #define WM8510_ADCVOL 0xf | ||
| 27 | #define WM8510_EQ1 0x12 | ||
| 28 | #define WM8510_EQ2 0x13 | ||
| 29 | #define WM8510_EQ3 0x14 | ||
| 30 | #define WM8510_EQ4 0x15 | ||
| 31 | #define WM8510_EQ5 0x16 | ||
| 32 | #define WM8510_DACLIM1 0x18 | ||
| 33 | #define WM8510_DACLIM2 0x19 | ||
| 34 | #define WM8510_NOTCH1 0x1b | ||
| 35 | #define WM8510_NOTCH2 0x1c | ||
| 36 | #define WM8510_NOTCH3 0x1d | ||
| 37 | #define WM8510_NOTCH4 0x1e | ||
| 38 | #define WM8510_ALC1 0x20 | ||
| 39 | #define WM8510_ALC2 0x21 | ||
| 40 | #define WM8510_ALC3 0x22 | ||
| 41 | #define WM8510_NGATE 0x23 | ||
| 42 | #define WM8510_PLLN 0x24 | ||
| 43 | #define WM8510_PLLK1 0x25 | ||
| 44 | #define WM8510_PLLK2 0x26 | ||
| 45 | #define WM8510_PLLK3 0x27 | ||
| 46 | #define WM8510_ATTEN 0x28 | ||
| 47 | #define WM8510_INPUT 0x2c | ||
| 48 | #define WM8510_INPPGA 0x2d | ||
| 49 | #define WM8510_ADCBOOST 0x2f | ||
| 50 | #define WM8510_OUTPUT 0x31 | ||
| 51 | #define WM8510_SPKMIX 0x32 | ||
| 52 | #define WM8510_SPKVOL 0x36 | ||
| 53 | #define WM8510_MONOMIX 0x38 | ||
| 54 | |||
| 55 | #define WM8510_CACHEREGNUM 57 | ||
| 56 | |||
| 57 | /* Clock divider Id's */ | ||
| 58 | #define WM8510_OPCLKDIV 0 | ||
| 59 | #define WM8510_MCLKDIV 1 | ||
| 60 | #define WM8510_ADCCLK 2 | ||
| 61 | #define WM8510_DACCLK 3 | ||
| 62 | #define WM8510_BCLKDIV 4 | ||
| 63 | |||
| 64 | /* DAC clock dividers */ | ||
| 65 | #define WM8510_DACCLK_F2 (1 << 3) | ||
| 66 | #define WM8510_DACCLK_F4 (0 << 3) | ||
| 67 | |||
| 68 | /* ADC clock dividers */ | ||
| 69 | #define WM8510_ADCCLK_F2 (1 << 3) | ||
| 70 | #define WM8510_ADCCLK_F4 (0 << 3) | ||
| 71 | |||
| 72 | /* PLL Out dividers */ | ||
| 73 | #define WM8510_OPCLKDIV_1 (0 << 4) | ||
| 74 | #define WM8510_OPCLKDIV_2 (1 << 4) | ||
| 75 | #define WM8510_OPCLKDIV_3 (2 << 4) | ||
| 76 | #define WM8510_OPCLKDIV_4 (3 << 4) | ||
| 77 | |||
| 78 | /* BCLK clock dividers */ | ||
| 79 | #define WM8510_BCLKDIV_1 (0 << 2) | ||
| 80 | #define WM8510_BCLKDIV_2 (1 << 2) | ||
| 81 | #define WM8510_BCLKDIV_4 (2 << 2) | ||
| 82 | #define WM8510_BCLKDIV_8 (3 << 2) | ||
| 83 | #define WM8510_BCLKDIV_16 (4 << 2) | ||
| 84 | #define WM8510_BCLKDIV_32 (5 << 2) | ||
| 85 | |||
| 86 | /* MCLK clock dividers */ | ||
| 87 | #define WM8510_MCLKDIV_1 (0 << 5) | ||
| 88 | #define WM8510_MCLKDIV_1_5 (1 << 5) | ||
| 89 | #define WM8510_MCLKDIV_2 (2 << 5) | ||
| 90 | #define WM8510_MCLKDIV_3 (3 << 5) | ||
| 91 | #define WM8510_MCLKDIV_4 (4 << 5) | ||
| 92 | #define WM8510_MCLKDIV_6 (5 << 5) | ||
| 93 | #define WM8510_MCLKDIV_8 (6 << 5) | ||
| 94 | #define WM8510_MCLKDIV_12 (7 << 5) | ||
| 95 | |||
| 96 | struct wm8510_setup_data { | ||
| 97 | unsigned short i2c_address; | ||
| 98 | }; | ||
| 99 | |||
| 100 | extern struct snd_soc_dai wm8510_dai; | ||
| 101 | extern struct snd_soc_codec_device soc_codec_dev_wm8510; | ||
| 102 | |||
| 103 | #endif | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 0cf9265fca8f..369d39c3f745 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
| @@ -31,25 +31,6 @@ | |||
| 31 | #define AUDIO_NAME "wm8731" | 31 | #define AUDIO_NAME "wm8731" |
| 32 | #define WM8731_VERSION "0.13" | 32 | #define WM8731_VERSION "0.13" |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * Debug | ||
| 36 | */ | ||
| 37 | |||
| 38 | #define WM8731_DEBUG 0 | ||
| 39 | |||
| 40 | #ifdef WM8731_DEBUG | ||
| 41 | #define dbg(format, arg...) \ | ||
| 42 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
| 43 | #else | ||
| 44 | #define dbg(format, arg...) do {} while (0) | ||
| 45 | #endif | ||
| 46 | #define err(format, arg...) \ | ||
| 47 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
| 48 | #define info(format, arg...) \ | ||
| 49 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
| 50 | #define warn(format, arg...) \ | ||
| 51 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
| 52 | |||
| 53 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 34 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
| 54 | 35 | ||
| 55 | /* codec private data */ | 36 | /* codec private data */ |
| @@ -193,7 +174,7 @@ SND_SOC_DAPM_INPUT("RLINEIN"), | |||
| 193 | SND_SOC_DAPM_INPUT("LLINEIN"), | 174 | SND_SOC_DAPM_INPUT("LLINEIN"), |
| 194 | }; | 175 | }; |
| 195 | 176 | ||
| 196 | static const char *intercon[][3] = { | 177 | static const struct snd_soc_dapm_route intercon[] = { |
| 197 | /* output mixer */ | 178 | /* output mixer */ |
| 198 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | 179 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, |
| 199 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | 180 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, |
| @@ -214,22 +195,14 @@ static const char *intercon[][3] = { | |||
| 214 | {"Line Input", NULL, "LLINEIN"}, | 195 | {"Line Input", NULL, "LLINEIN"}, |
| 215 | {"Line Input", NULL, "RLINEIN"}, | 196 | {"Line Input", NULL, "RLINEIN"}, |
| 216 | {"Mic Bias", NULL, "MICIN"}, | 197 | {"Mic Bias", NULL, "MICIN"}, |
| 217 | |||
| 218 | /* terminator */ | ||
| 219 | {NULL, NULL, NULL}, | ||
| 220 | }; | 198 | }; |
| 221 | 199 | ||
| 222 | static int wm8731_add_widgets(struct snd_soc_codec *codec) | 200 | static int wm8731_add_widgets(struct snd_soc_codec *codec) |
| 223 | { | 201 | { |
| 224 | int i; | 202 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
| 225 | 203 | ARRAY_SIZE(wm8731_dapm_widgets)); | |
| 226 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) | ||
| 227 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | ||
| 228 | 204 | ||
| 229 | /* set up audio path interconnects */ | 205 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
| 230 | for (i = 0; intercon[i][0] != NULL; i++) | ||
| 231 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
| 232 | intercon[i][1], intercon[i][2]); | ||
| 233 | 206 | ||
| 234 | snd_soc_dapm_new_widgets(codec); | 207 | snd_soc_dapm_new_widgets(codec); |
| 235 | return 0; | 208 | return 0; |
| @@ -345,7 +318,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream) | |||
| 345 | } | 318 | } |
| 346 | } | 319 | } |
| 347 | 320 | ||
| 348 | static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) | 321 | static int wm8731_mute(struct snd_soc_dai *dai, int mute) |
| 349 | { | 322 | { |
| 350 | struct snd_soc_codec *codec = dai->codec; | 323 | struct snd_soc_codec *codec = dai->codec; |
| 351 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; | 324 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; |
| @@ -357,7 +330,7 @@ static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) | |||
| 357 | return 0; | 330 | return 0; |
| 358 | } | 331 | } |
| 359 | 332 | ||
| 360 | static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 333 | static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
| 361 | int clk_id, unsigned int freq, int dir) | 334 | int clk_id, unsigned int freq, int dir) |
| 362 | { | 335 | { |
| 363 | struct snd_soc_codec *codec = codec_dai->codec; | 336 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -376,7 +349,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
| 376 | } | 349 | } |
| 377 | 350 | ||
| 378 | 351 | ||
| 379 | static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 352 | static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 380 | unsigned int fmt) | 353 | unsigned int fmt) |
| 381 | { | 354 | { |
| 382 | struct snd_soc_codec *codec = codec_dai->codec; | 355 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -435,29 +408,29 @@ static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 435 | return 0; | 408 | return 0; |
| 436 | } | 409 | } |
| 437 | 410 | ||
| 438 | static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) | 411 | static int wm8731_set_bias_level(struct snd_soc_codec *codec, |
| 412 | enum snd_soc_bias_level level) | ||
| 439 | { | 413 | { |
| 440 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | 414 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; |
| 441 | 415 | ||
| 442 | switch (event) { | 416 | switch (level) { |
| 443 | case SNDRV_CTL_POWER_D0: /* full On */ | 417 | case SND_SOC_BIAS_ON: |
| 444 | /* vref/mid, osc on, dac unmute */ | 418 | /* vref/mid, osc on, dac unmute */ |
| 445 | wm8731_write(codec, WM8731_PWR, reg); | 419 | wm8731_write(codec, WM8731_PWR, reg); |
| 446 | break; | 420 | break; |
| 447 | case SNDRV_CTL_POWER_D1: /* partial On */ | 421 | case SND_SOC_BIAS_PREPARE: |
| 448 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
| 449 | break; | 422 | break; |
| 450 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 423 | case SND_SOC_BIAS_STANDBY: |
| 451 | /* everything off except vref/vmid, */ | 424 | /* everything off except vref/vmid, */ |
| 452 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); | 425 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); |
| 453 | break; | 426 | break; |
| 454 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 427 | case SND_SOC_BIAS_OFF: |
| 455 | /* everything off, dac mute, inactive */ | 428 | /* everything off, dac mute, inactive */ |
| 456 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 429 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
| 457 | wm8731_write(codec, WM8731_PWR, 0xffff); | 430 | wm8731_write(codec, WM8731_PWR, 0xffff); |
| 458 | break; | 431 | break; |
| 459 | } | 432 | } |
| 460 | codec->dapm_state = event; | 433 | codec->bias_level = level; |
| 461 | return 0; | 434 | return 0; |
| 462 | } | 435 | } |
| 463 | 436 | ||
| @@ -470,7 +443,7 @@ static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) | |||
| 470 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 443 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| 471 | SNDRV_PCM_FMTBIT_S24_LE) | 444 | SNDRV_PCM_FMTBIT_S24_LE) |
| 472 | 445 | ||
| 473 | struct snd_soc_codec_dai wm8731_dai = { | 446 | struct snd_soc_dai wm8731_dai = { |
| 474 | .name = "WM8731", | 447 | .name = "WM8731", |
| 475 | .playback = { | 448 | .playback = { |
| 476 | .stream_name = "Playback", | 449 | .stream_name = "Playback", |
| @@ -503,7 +476,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 503 | struct snd_soc_codec *codec = socdev->codec; | 476 | struct snd_soc_codec *codec = socdev->codec; |
| 504 | 477 | ||
| 505 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 478 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
| 506 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 479 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 507 | return 0; | 480 | return 0; |
| 508 | } | 481 | } |
| 509 | 482 | ||
| @@ -521,8 +494,8 @@ static int wm8731_resume(struct platform_device *pdev) | |||
| 521 | data[1] = cache[i] & 0x00ff; | 494 | data[1] = cache[i] & 0x00ff; |
| 522 | codec->hw_write(codec->control_data, data, 2); | 495 | codec->hw_write(codec->control_data, data, 2); |
| 523 | } | 496 | } |
| 524 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 497 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 525 | wm8731_dapm_event(codec, codec->suspend_dapm_state); | 498 | wm8731_set_bias_level(codec, codec->suspend_bias_level); |
| 526 | return 0; | 499 | return 0; |
| 527 | } | 500 | } |
| 528 | 501 | ||
| @@ -539,10 +512,10 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
| 539 | codec->owner = THIS_MODULE; | 512 | codec->owner = THIS_MODULE; |
| 540 | codec->read = wm8731_read_reg_cache; | 513 | codec->read = wm8731_read_reg_cache; |
| 541 | codec->write = wm8731_write; | 514 | codec->write = wm8731_write; |
| 542 | codec->dapm_event = wm8731_dapm_event; | 515 | codec->set_bias_level = wm8731_set_bias_level; |
| 543 | codec->dai = &wm8731_dai; | 516 | codec->dai = &wm8731_dai; |
| 544 | codec->num_dai = 1; | 517 | codec->num_dai = 1; |
| 545 | codec->reg_cache_size = sizeof(wm8731_reg); | 518 | codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); |
| 546 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); | 519 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); |
| 547 | if (codec->reg_cache == NULL) | 520 | if (codec->reg_cache == NULL) |
| 548 | return -ENOMEM; | 521 | return -ENOMEM; |
| @@ -557,7 +530,7 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
| 557 | } | 530 | } |
| 558 | 531 | ||
| 559 | /* power on device */ | 532 | /* power on device */ |
| 560 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 533 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 561 | 534 | ||
| 562 | /* set the update bits */ | 535 | /* set the update bits */ |
| 563 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | 536 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); |
| @@ -632,13 +605,13 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
| 632 | 605 | ||
| 633 | ret = i2c_attach_client(i2c); | 606 | ret = i2c_attach_client(i2c); |
| 634 | if (ret < 0) { | 607 | if (ret < 0) { |
| 635 | err("failed to attach codec at addr %x\n", addr); | 608 | pr_err("failed to attach codec at addr %x\n", addr); |
| 636 | goto err; | 609 | goto err; |
| 637 | } | 610 | } |
| 638 | 611 | ||
| 639 | ret = wm8731_init(socdev); | 612 | ret = wm8731_init(socdev); |
| 640 | if (ret < 0) { | 613 | if (ret < 0) { |
| 641 | err("failed to initialise WM8731\n"); | 614 | pr_err("failed to initialise WM8731\n"); |
| 642 | goto err; | 615 | goto err; |
| 643 | } | 616 | } |
| 644 | return ret; | 617 | return ret; |
| @@ -689,7 +662,7 @@ static int wm8731_probe(struct platform_device *pdev) | |||
| 689 | struct wm8731_priv *wm8731; | 662 | struct wm8731_priv *wm8731; |
| 690 | int ret = 0; | 663 | int ret = 0; |
| 691 | 664 | ||
| 692 | info("WM8731 Audio Codec %s", WM8731_VERSION); | 665 | pr_info("WM8731 Audio Codec %s", WM8731_VERSION); |
| 693 | 666 | ||
| 694 | setup = socdev->codec_data; | 667 | setup = socdev->codec_data; |
| 695 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 668 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
| @@ -730,7 +703,7 @@ static int wm8731_remove(struct platform_device *pdev) | |||
| 730 | struct snd_soc_codec *codec = socdev->codec; | 703 | struct snd_soc_codec *codec = socdev->codec; |
| 731 | 704 | ||
| 732 | if (codec->control_data) | 705 | if (codec->control_data) |
| 733 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 706 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 734 | 707 | ||
| 735 | snd_soc_free_pcms(socdev); | 708 | snd_soc_free_pcms(socdev); |
| 736 | snd_soc_dapm_free(socdev); | 709 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 5bcab6a7afb4..99f2e3c60e33 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h | |||
| @@ -38,7 +38,7 @@ struct wm8731_setup_data { | |||
| 38 | unsigned short i2c_address; | 38 | unsigned short i2c_address; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | extern struct snd_soc_codec_dai wm8731_dai; | 41 | extern struct snd_soc_dai wm8731_dai; |
| 42 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; | 42 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; |
| 43 | 43 | ||
| 44 | #endif | 44 | #endif |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 16cd5d4d5ad9..e23cb09f0d14 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
| @@ -31,25 +31,6 @@ | |||
| 31 | #define AUDIO_NAME "WM8750" | 31 | #define AUDIO_NAME "WM8750" |
| 32 | #define WM8750_VERSION "0.12" | 32 | #define WM8750_VERSION "0.12" |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * Debug | ||
| 36 | */ | ||
| 37 | |||
| 38 | #define WM8750_DEBUG 0 | ||
| 39 | |||
| 40 | #ifdef WM8750_DEBUG | ||
| 41 | #define dbg(format, arg...) \ | ||
| 42 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
| 43 | #else | ||
| 44 | #define dbg(format, arg...) do {} while (0) | ||
| 45 | #endif | ||
| 46 | #define err(format, arg...) \ | ||
| 47 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
| 48 | #define info(format, arg...) \ | ||
| 49 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
| 50 | #define warn(format, arg...) \ | ||
| 51 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
| 52 | |||
| 53 | /* codec private data */ | 34 | /* codec private data */ |
| 54 | struct wm8750_priv { | 35 | struct wm8750_priv { |
| 55 | unsigned int sysclk; | 36 | unsigned int sysclk; |
| @@ -378,7 +359,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | |||
| 378 | SND_SOC_DAPM_INPUT("RINPUT3"), | 359 | SND_SOC_DAPM_INPUT("RINPUT3"), |
| 379 | }; | 360 | }; |
| 380 | 361 | ||
| 381 | static const char *audio_map[][3] = { | 362 | static const struct snd_soc_dapm_route audio_map[] = { |
| 382 | /* left mixer */ | 363 | /* left mixer */ |
| 383 | {"Left Mixer", "Playback Switch", "Left DAC"}, | 364 | {"Left Mixer", "Playback Switch", "Left DAC"}, |
| 384 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | 365 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, |
| @@ -470,22 +451,14 @@ static const char *audio_map[][3] = { | |||
| 470 | /* ADC */ | 451 | /* ADC */ |
| 471 | {"Left ADC", NULL, "Left ADC Mux"}, | 452 | {"Left ADC", NULL, "Left ADC Mux"}, |
| 472 | {"Right ADC", NULL, "Right ADC Mux"}, | 453 | {"Right ADC", NULL, "Right ADC Mux"}, |
| 473 | |||
| 474 | /* terminator */ | ||
| 475 | {NULL, NULL, NULL}, | ||
| 476 | }; | 454 | }; |
| 477 | 455 | ||
| 478 | static int wm8750_add_widgets(struct snd_soc_codec *codec) | 456 | static int wm8750_add_widgets(struct snd_soc_codec *codec) |
| 479 | { | 457 | { |
| 480 | int i; | 458 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
| 481 | 459 | ARRAY_SIZE(wm8750_dapm_widgets)); | |
| 482 | for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) | ||
| 483 | snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); | ||
| 484 | 460 | ||
| 485 | /* set up audio path audio_mapnects */ | 461 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 486 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
| 487 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 488 | audio_map[i][1], audio_map[i][2]); | ||
| 489 | 462 | ||
| 490 | snd_soc_dapm_new_widgets(codec); | 463 | snd_soc_dapm_new_widgets(codec); |
| 491 | return 0; | 464 | return 0; |
| @@ -563,7 +536,7 @@ static inline int get_coeff(int mclk, int rate) | |||
| 563 | return -EINVAL; | 536 | return -EINVAL; |
| 564 | } | 537 | } |
| 565 | 538 | ||
| 566 | static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 539 | static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
| 567 | int clk_id, unsigned int freq, int dir) | 540 | int clk_id, unsigned int freq, int dir) |
| 568 | { | 541 | { |
| 569 | struct snd_soc_codec *codec = codec_dai->codec; | 542 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -581,7 +554,7 @@ static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
| 581 | return -EINVAL; | 554 | return -EINVAL; |
| 582 | } | 555 | } |
| 583 | 556 | ||
| 584 | static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 557 | static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 585 | unsigned int fmt) | 558 | unsigned int fmt) |
| 586 | { | 559 | { |
| 587 | struct snd_soc_codec *codec = codec_dai->codec; | 560 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -674,7 +647,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 674 | return 0; | 647 | return 0; |
| 675 | } | 648 | } |
| 676 | 649 | ||
| 677 | static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) | 650 | static int wm8750_mute(struct snd_soc_dai *dai, int mute) |
| 678 | { | 651 | { |
| 679 | struct snd_soc_codec *codec = dai->codec; | 652 | struct snd_soc_codec *codec = dai->codec; |
| 680 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; | 653 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; |
| @@ -686,29 +659,29 @@ static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) | |||
| 686 | return 0; | 659 | return 0; |
| 687 | } | 660 | } |
| 688 | 661 | ||
| 689 | static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | 662 | static int wm8750_set_bias_level(struct snd_soc_codec *codec, |
| 663 | enum snd_soc_bias_level level) | ||
| 690 | { | 664 | { |
| 691 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; | 665 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; |
| 692 | 666 | ||
| 693 | switch (event) { | 667 | switch (level) { |
| 694 | case SNDRV_CTL_POWER_D0: /* full On */ | 668 | case SND_SOC_BIAS_ON: |
| 695 | /* set vmid to 50k and unmute dac */ | 669 | /* set vmid to 50k and unmute dac */ |
| 696 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); | 670 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); |
| 697 | break; | 671 | break; |
| 698 | case SNDRV_CTL_POWER_D1: /* partial On */ | 672 | case SND_SOC_BIAS_PREPARE: |
| 699 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
| 700 | /* set vmid to 5k for quick power up */ | 673 | /* set vmid to 5k for quick power up */ |
| 701 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | 674 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); |
| 702 | break; | 675 | break; |
| 703 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 676 | case SND_SOC_BIAS_STANDBY: |
| 704 | /* mute dac and set vmid to 500k, enable VREF */ | 677 | /* mute dac and set vmid to 500k, enable VREF */ |
| 705 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); | 678 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); |
| 706 | break; | 679 | break; |
| 707 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 680 | case SND_SOC_BIAS_OFF: |
| 708 | wm8750_write(codec, WM8750_PWR1, 0x0001); | 681 | wm8750_write(codec, WM8750_PWR1, 0x0001); |
| 709 | break; | 682 | break; |
| 710 | } | 683 | } |
| 711 | codec->dapm_state = event; | 684 | codec->bias_level = level; |
| 712 | return 0; | 685 | return 0; |
| 713 | } | 686 | } |
| 714 | 687 | ||
| @@ -719,7 +692,7 @@ static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | |||
| 719 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 692 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| 720 | SNDRV_PCM_FMTBIT_S24_LE) | 693 | SNDRV_PCM_FMTBIT_S24_LE) |
| 721 | 694 | ||
| 722 | struct snd_soc_codec_dai wm8750_dai = { | 695 | struct snd_soc_dai wm8750_dai = { |
| 723 | .name = "WM8750", | 696 | .name = "WM8750", |
| 724 | .playback = { | 697 | .playback = { |
| 725 | .stream_name = "Playback", | 698 | .stream_name = "Playback", |
| @@ -748,7 +721,7 @@ static void wm8750_work(struct work_struct *work) | |||
| 748 | { | 721 | { |
| 749 | struct snd_soc_codec *codec = | 722 | struct snd_soc_codec *codec = |
| 750 | container_of(work, struct snd_soc_codec, delayed_work.work); | 723 | container_of(work, struct snd_soc_codec, delayed_work.work); |
| 751 | wm8750_dapm_event(codec, codec->dapm_state); | 724 | wm8750_set_bias_level(codec, codec->bias_level); |
| 752 | } | 725 | } |
| 753 | 726 | ||
| 754 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | 727 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) |
| @@ -756,7 +729,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 756 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 729 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 757 | struct snd_soc_codec *codec = socdev->codec; | 730 | struct snd_soc_codec *codec = socdev->codec; |
| 758 | 731 | ||
| 759 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 732 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 760 | return 0; | 733 | return 0; |
| 761 | } | 734 | } |
| 762 | 735 | ||
| @@ -777,12 +750,12 @@ static int wm8750_resume(struct platform_device *pdev) | |||
| 777 | codec->hw_write(codec->control_data, data, 2); | 750 | codec->hw_write(codec->control_data, data, 2); |
| 778 | } | 751 | } |
| 779 | 752 | ||
| 780 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 753 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 781 | 754 | ||
| 782 | /* charge wm8750 caps */ | 755 | /* charge wm8750 caps */ |
| 783 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | 756 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
| 784 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | 757 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
| 785 | codec->dapm_state = SNDRV_CTL_POWER_D0; | 758 | codec->bias_level = SND_SOC_BIAS_ON; |
| 786 | schedule_delayed_work(&codec->delayed_work, | 759 | schedule_delayed_work(&codec->delayed_work, |
| 787 | msecs_to_jiffies(1000)); | 760 | msecs_to_jiffies(1000)); |
| 788 | } | 761 | } |
| @@ -803,10 +776,10 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
| 803 | codec->owner = THIS_MODULE; | 776 | codec->owner = THIS_MODULE; |
| 804 | codec->read = wm8750_read_reg_cache; | 777 | codec->read = wm8750_read_reg_cache; |
| 805 | codec->write = wm8750_write; | 778 | codec->write = wm8750_write; |
| 806 | codec->dapm_event = wm8750_dapm_event; | 779 | codec->set_bias_level = wm8750_set_bias_level; |
| 807 | codec->dai = &wm8750_dai; | 780 | codec->dai = &wm8750_dai; |
| 808 | codec->num_dai = 1; | 781 | codec->num_dai = 1; |
| 809 | codec->reg_cache_size = sizeof(wm8750_reg); | 782 | codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); |
| 810 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); | 783 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); |
| 811 | if (codec->reg_cache == NULL) | 784 | if (codec->reg_cache == NULL) |
| 812 | return -ENOMEM; | 785 | return -ENOMEM; |
| @@ -821,8 +794,8 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
| 821 | } | 794 | } |
| 822 | 795 | ||
| 823 | /* charge output caps */ | 796 | /* charge output caps */ |
| 824 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | 797 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
| 825 | codec->dapm_state = SNDRV_CTL_POWER_D3hot; | 798 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
| 826 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | 799 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); |
| 827 | 800 | ||
| 828 | /* set the update bits */ | 801 | /* set the update bits */ |
| @@ -904,13 +877,13 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
| 904 | 877 | ||
| 905 | ret = i2c_attach_client(i2c); | 878 | ret = i2c_attach_client(i2c); |
| 906 | if (ret < 0) { | 879 | if (ret < 0) { |
| 907 | err("failed to attach codec at addr %x\n", addr); | 880 | pr_err("failed to attach codec at addr %x\n", addr); |
| 908 | goto err; | 881 | goto err; |
| 909 | } | 882 | } |
| 910 | 883 | ||
| 911 | ret = wm8750_init(socdev); | 884 | ret = wm8750_init(socdev); |
| 912 | if (ret < 0) { | 885 | if (ret < 0) { |
| 913 | err("failed to initialise WM8750\n"); | 886 | pr_err("failed to initialise WM8750\n"); |
| 914 | goto err; | 887 | goto err; |
| 915 | } | 888 | } |
| 916 | return ret; | 889 | return ret; |
| @@ -961,7 +934,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
| 961 | struct wm8750_priv *wm8750; | 934 | struct wm8750_priv *wm8750; |
| 962 | int ret = 0; | 935 | int ret = 0; |
| 963 | 936 | ||
| 964 | info("WM8750 Audio Codec %s", WM8750_VERSION); | 937 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
| 965 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 938 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
| 966 | if (codec == NULL) | 939 | if (codec == NULL) |
| 967 | return -ENOMEM; | 940 | return -ENOMEM; |
| @@ -1021,7 +994,7 @@ static int wm8750_remove(struct platform_device *pdev) | |||
| 1021 | struct snd_soc_codec *codec = socdev->codec; | 994 | struct snd_soc_codec *codec = socdev->codec; |
| 1022 | 995 | ||
| 1023 | if (codec->control_data) | 996 | if (codec->control_data) |
| 1024 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 997 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1025 | run_delayed_work(&codec->delayed_work); | 998 | run_delayed_work(&codec->delayed_work); |
| 1026 | snd_soc_free_pcms(socdev); | 999 | snd_soc_free_pcms(socdev); |
| 1027 | snd_soc_dapm_free(socdev); | 1000 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index a97a54a6348e..8ef30e628b21 100644 --- a/sound/soc/codecs/wm8750.h +++ b/sound/soc/codecs/wm8750.h | |||
| @@ -61,7 +61,7 @@ struct wm8750_setup_data { | |||
| 61 | unsigned short i2c_address; | 61 | unsigned short i2c_address; |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | extern struct snd_soc_codec_dai wm8750_dai; | 64 | extern struct snd_soc_dai wm8750_dai; |
| 65 | extern struct snd_soc_codec_device soc_codec_dev_wm8750; | 65 | extern struct snd_soc_codec_device soc_codec_dev_wm8750; |
| 66 | 66 | ||
| 67 | #endif | 67 | #endif |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index fb41826c4c4c..8604809f0c36 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
| @@ -55,25 +55,6 @@ | |||
| 55 | #define AUDIO_NAME "wm8753" | 55 | #define AUDIO_NAME "wm8753" |
| 56 | #define WM8753_VERSION "0.16" | 56 | #define WM8753_VERSION "0.16" |
| 57 | 57 | ||
| 58 | /* | ||
| 59 | * Debug | ||
| 60 | */ | ||
| 61 | |||
| 62 | #define WM8753_DEBUG 0 | ||
| 63 | |||
| 64 | #ifdef WM8753_DEBUG | ||
| 65 | #define dbg(format, arg...) \ | ||
| 66 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
| 67 | #else | ||
| 68 | #define dbg(format, arg...) do {} while (0) | ||
| 69 | #endif | ||
| 70 | #define err(format, arg...) \ | ||
| 71 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
| 72 | #define info(format, arg...) \ | ||
| 73 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
| 74 | #define warn(format, arg...) \ | ||
| 75 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
| 76 | |||
| 77 | static int caps_charge = 2000; | 58 | static int caps_charge = 2000; |
| 78 | module_param(caps_charge, int, 0); | 59 | module_param(caps_charge, int, 0); |
| 79 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 60 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
| @@ -260,28 +241,50 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
| 260 | return 1; | 241 | return 1; |
| 261 | } | 242 | } |
| 262 | 243 | ||
| 263 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | 244 | static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); |
| 245 | static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); | ||
| 246 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); | ||
| 247 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | ||
| 248 | static const unsigned int out_tlv[] = { | ||
| 249 | TLV_DB_RANGE_HEAD(2), | ||
| 250 | /* 0000000 - 0101111 = "Analogue mute" */ | ||
| 251 | 0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0), | ||
| 252 | 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0), | ||
| 253 | }; | ||
| 254 | static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0); | ||
| 255 | static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0); | ||
| 256 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); | ||
| 264 | 257 | ||
| 265 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { | 258 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { |
| 266 | SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0), | 259 | SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv), |
| 267 | 260 | ||
| 268 | SOC_DOUBLE_R("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0), | 261 | SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0, |
| 269 | 262 | adc_tlv), | |
| 270 | SOC_DOUBLE_R("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, 0, 127, 0), | 263 | |
| 271 | SOC_DOUBLE_R("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, 127, 0), | 264 | SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, |
| 272 | 265 | 0, 127, 0, out_tlv), | |
| 273 | SOC_SINGLE("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0), | 266 | SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, |
| 274 | 267 | 127, 0, out_tlv), | |
| 275 | SOC_DOUBLE_R("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, 1), | 268 | |
| 276 | SOC_DOUBLE_R("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, 7, 1), | 269 | SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv), |
| 277 | SOC_DOUBLE_R("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, 1), | 270 | |
| 278 | 271 | SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, | |
| 279 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, 1, 0), | 272 | 1, mix_tlv), |
| 280 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, 1, 0), | 273 | SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, |
| 281 | 274 | 7, 1, mix_tlv), | |
| 282 | SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1), | 275 | SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, |
| 283 | SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1), | 276 | 1, voice_mix_tlv), |
| 284 | SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1), | 277 | |
| 278 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, | ||
| 279 | 1, 0), | ||
| 280 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, | ||
| 281 | 1, 0), | ||
| 282 | |||
| 283 | SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv), | ||
| 284 | SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1, | ||
| 285 | mix_tlv), | ||
| 286 | SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1, | ||
| 287 | voice_mix_tlv), | ||
| 285 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), | 288 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), |
| 286 | 289 | ||
| 287 | SOC_ENUM("Bass Boost", wm8753_enum[0]), | 290 | SOC_ENUM("Bass Boost", wm8753_enum[0]), |
| @@ -291,10 +294,13 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1), | |||
| 291 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), | 294 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), |
| 292 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), | 295 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), |
| 293 | 296 | ||
| 294 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv), | 297 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, |
| 295 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv), | 298 | rec_mix_tlv), |
| 299 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, | ||
| 300 | rec_mix_tlv), | ||
| 296 | 301 | ||
| 297 | SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0), | 302 | SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0, |
| 303 | pga_tlv), | ||
| 298 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), | 304 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), |
| 299 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), | 305 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), |
| 300 | 306 | ||
| @@ -326,8 +332,8 @@ SOC_ENUM("De-emphasis", wm8753_enum[8]), | |||
| 326 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), | 332 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), |
| 327 | SOC_ENUM("Playback Phase", wm8753_enum[10]), | 333 | SOC_ENUM("Playback Phase", wm8753_enum[10]), |
| 328 | 334 | ||
| 329 | SOC_SINGLE("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0), | 335 | SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv), |
| 330 | SOC_SINGLE("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0), | 336 | SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv), |
| 331 | 337 | ||
| 332 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), | 338 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), |
| 333 | 339 | ||
| @@ -523,7 +529,7 @@ SND_SOC_DAPM_INPUT("MIC2"), | |||
| 523 | SND_SOC_DAPM_VMID("VREF"), | 529 | SND_SOC_DAPM_VMID("VREF"), |
| 524 | }; | 530 | }; |
| 525 | 531 | ||
| 526 | static const char *audio_map[][3] = { | 532 | static const struct snd_soc_dapm_route audio_map[] = { |
| 527 | /* left mixer */ | 533 | /* left mixer */ |
| 528 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, | 534 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, |
| 529 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, | 535 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, |
| @@ -674,23 +680,14 @@ static const char *audio_map[][3] = { | |||
| 674 | 680 | ||
| 675 | /* ACOP */ | 681 | /* ACOP */ |
| 676 | {"ACOP", NULL, "ALC Mixer"}, | 682 | {"ACOP", NULL, "ALC Mixer"}, |
| 677 | |||
| 678 | /* terminator */ | ||
| 679 | {NULL, NULL, NULL}, | ||
| 680 | }; | 683 | }; |
| 681 | 684 | ||
| 682 | static int wm8753_add_widgets(struct snd_soc_codec *codec) | 685 | static int wm8753_add_widgets(struct snd_soc_codec *codec) |
| 683 | { | 686 | { |
| 684 | int i; | 687 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, |
| 688 | ARRAY_SIZE(wm8753_dapm_widgets)); | ||
| 685 | 689 | ||
| 686 | for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++) | 690 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 687 | snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]); | ||
| 688 | |||
| 689 | /* set up the WM8753 audio map */ | ||
| 690 | for (i = 0; audio_map[i][0] != NULL; i++) { | ||
| 691 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 692 | audio_map[i][1], audio_map[i][2]); | ||
| 693 | } | ||
| 694 | 691 | ||
| 695 | snd_soc_dapm_new_widgets(codec); | 692 | snd_soc_dapm_new_widgets(codec); |
| 696 | return 0; | 693 | return 0; |
| @@ -743,7 +740,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
| 743 | pll_div->k = K; | 740 | pll_div->k = K; |
| 744 | } | 741 | } |
| 745 | 742 | ||
| 746 | static int wm8753_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | 743 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, |
| 747 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 744 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
| 748 | { | 745 | { |
| 749 | u16 reg, enable; | 746 | u16 reg, enable; |
| @@ -866,7 +863,7 @@ static int get_coeff(int mclk, int rate) | |||
| 866 | /* | 863 | /* |
| 867 | * Clock after PLL and dividers | 864 | * Clock after PLL and dividers |
| 868 | */ | 865 | */ |
| 869 | static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 866 | static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
| 870 | int clk_id, unsigned int freq, int dir) | 867 | int clk_id, unsigned int freq, int dir) |
| 871 | { | 868 | { |
| 872 | struct snd_soc_codec *codec = codec_dai->codec; | 869 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -893,7 +890,7 @@ static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
| 893 | /* | 890 | /* |
| 894 | * Set's ADC and Voice DAC format. | 891 | * Set's ADC and Voice DAC format. |
| 895 | */ | 892 | */ |
| 896 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 893 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 897 | unsigned int fmt) | 894 | unsigned int fmt) |
| 898 | { | 895 | { |
| 899 | struct snd_soc_codec *codec = codec_dai->codec; | 896 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -963,7 +960,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 963 | /* | 960 | /* |
| 964 | * Set's PCM dai fmt and BCLK. | 961 | * Set's PCM dai fmt and BCLK. |
| 965 | */ | 962 | */ |
| 966 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 963 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 967 | unsigned int fmt) | 964 | unsigned int fmt) |
| 968 | { | 965 | { |
| 969 | struct snd_soc_codec *codec = codec_dai->codec; | 966 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -1029,7 +1026,7 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 1029 | return 0; | 1026 | return 0; |
| 1030 | } | 1027 | } |
| 1031 | 1028 | ||
| 1032 | static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | 1029 | static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
| 1033 | int div_id, int div) | 1030 | int div_id, int div) |
| 1034 | { | 1031 | { |
| 1035 | struct snd_soc_codec *codec = codec_dai->codec; | 1032 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -1057,7 +1054,7 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | |||
| 1057 | /* | 1054 | /* |
| 1058 | * Set's HiFi DAC format. | 1055 | * Set's HiFi DAC format. |
| 1059 | */ | 1056 | */ |
| 1060 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1057 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1061 | unsigned int fmt) | 1058 | unsigned int fmt) |
| 1062 | { | 1059 | { |
| 1063 | struct snd_soc_codec *codec = codec_dai->codec; | 1060 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -1090,7 +1087,7 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 1090 | /* | 1087 | /* |
| 1091 | * Set's I2S DAI format. | 1088 | * Set's I2S DAI format. |
| 1092 | */ | 1089 | */ |
| 1093 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1090 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1094 | unsigned int fmt) | 1091 | unsigned int fmt) |
| 1095 | { | 1092 | { |
| 1096 | struct snd_soc_codec *codec = codec_dai->codec; | 1093 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -1198,7 +1195,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | |||
| 1198 | return 0; | 1195 | return 0; |
| 1199 | } | 1196 | } |
| 1200 | 1197 | ||
| 1201 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1198 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1202 | unsigned int fmt) | 1199 | unsigned int fmt) |
| 1203 | { | 1200 | { |
| 1204 | struct snd_soc_codec *codec = codec_dai->codec; | 1201 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -1213,7 +1210,7 @@ static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 1213 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); | 1210 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); |
| 1214 | } | 1211 | } |
| 1215 | 1212 | ||
| 1216 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1213 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1217 | unsigned int fmt) | 1214 | unsigned int fmt) |
| 1218 | { | 1215 | { |
| 1219 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1216 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) |
| @@ -1221,7 +1218,7 @@ static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 1221 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1218 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
| 1222 | } | 1219 | } |
| 1223 | 1220 | ||
| 1224 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1221 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1225 | unsigned int fmt) | 1222 | unsigned int fmt) |
| 1226 | { | 1223 | { |
| 1227 | struct snd_soc_codec *codec = codec_dai->codec; | 1224 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -1236,7 +1233,7 @@ static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 1236 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1233 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
| 1237 | } | 1234 | } |
| 1238 | 1235 | ||
| 1239 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1236 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 1240 | unsigned int fmt) | 1237 | unsigned int fmt) |
| 1241 | { | 1238 | { |
| 1242 | struct snd_soc_codec *codec = codec_dai->codec; | 1239 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -1253,7 +1250,7 @@ static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 1253 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1250 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
| 1254 | } | 1251 | } |
| 1255 | 1252 | ||
| 1256 | static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute) | 1253 | static int wm8753_mute(struct snd_soc_dai *dai, int mute) |
| 1257 | { | 1254 | { |
| 1258 | struct snd_soc_codec *codec = dai->codec; | 1255 | struct snd_soc_codec *codec = dai->codec; |
| 1259 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; | 1256 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; |
| @@ -1274,29 +1271,29 @@ static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute) | |||
| 1274 | return 0; | 1271 | return 0; |
| 1275 | } | 1272 | } |
| 1276 | 1273 | ||
| 1277 | static int wm8753_dapm_event(struct snd_soc_codec *codec, int event) | 1274 | static int wm8753_set_bias_level(struct snd_soc_codec *codec, |
| 1275 | enum snd_soc_bias_level level) | ||
| 1278 | { | 1276 | { |
| 1279 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; | 1277 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; |
| 1280 | 1278 | ||
| 1281 | switch (event) { | 1279 | switch (level) { |
| 1282 | case SNDRV_CTL_POWER_D0: /* full On */ | 1280 | case SND_SOC_BIAS_ON: |
| 1283 | /* set vmid to 50k and unmute dac */ | 1281 | /* set vmid to 50k and unmute dac */ |
| 1284 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); | 1282 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); |
| 1285 | break; | 1283 | break; |
| 1286 | case SNDRV_CTL_POWER_D1: /* partial On */ | 1284 | case SND_SOC_BIAS_PREPARE: |
| 1287 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
| 1288 | /* set vmid to 5k for quick power up */ | 1285 | /* set vmid to 5k for quick power up */ |
| 1289 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); | 1286 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); |
| 1290 | break; | 1287 | break; |
| 1291 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 1288 | case SND_SOC_BIAS_STANDBY: |
| 1292 | /* mute dac and set vmid to 500k, enable VREF */ | 1289 | /* mute dac and set vmid to 500k, enable VREF */ |
| 1293 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); | 1290 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); |
| 1294 | break; | 1291 | break; |
| 1295 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 1292 | case SND_SOC_BIAS_OFF: |
| 1296 | wm8753_write(codec, WM8753_PWR1, 0x0001); | 1293 | wm8753_write(codec, WM8753_PWR1, 0x0001); |
| 1297 | break; | 1294 | break; |
| 1298 | } | 1295 | } |
| 1299 | codec->dapm_state = event; | 1296 | codec->bias_level = level; |
| 1300 | return 0; | 1297 | return 0; |
| 1301 | } | 1298 | } |
| 1302 | 1299 | ||
| @@ -1319,7 +1316,7 @@ static int wm8753_dapm_event(struct snd_soc_codec *codec, int event) | |||
| 1319 | * 3. Voice disabled - HIFI over HIFI | 1316 | * 3. Voice disabled - HIFI over HIFI |
| 1320 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1317 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
| 1321 | */ | 1318 | */ |
| 1322 | static const struct snd_soc_codec_dai wm8753_all_dai[] = { | 1319 | static const struct snd_soc_dai wm8753_all_dai[] = { |
| 1323 | /* DAI HiFi mode 1 */ | 1320 | /* DAI HiFi mode 1 */ |
| 1324 | { .name = "WM8753 HiFi", | 1321 | { .name = "WM8753 HiFi", |
| 1325 | .id = 1, | 1322 | .id = 1, |
| @@ -1459,7 +1456,7 @@ static const struct snd_soc_codec_dai wm8753_all_dai[] = { | |||
| 1459 | }, | 1456 | }, |
| 1460 | }; | 1457 | }; |
| 1461 | 1458 | ||
| 1462 | struct snd_soc_codec_dai wm8753_dai[2]; | 1459 | struct snd_soc_dai wm8753_dai[2]; |
| 1463 | EXPORT_SYMBOL_GPL(wm8753_dai); | 1460 | EXPORT_SYMBOL_GPL(wm8753_dai); |
| 1464 | 1461 | ||
| 1465 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | 1462 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) |
| @@ -1500,7 +1497,7 @@ static void wm8753_work(struct work_struct *work) | |||
| 1500 | { | 1497 | { |
| 1501 | struct snd_soc_codec *codec = | 1498 | struct snd_soc_codec *codec = |
| 1502 | container_of(work, struct snd_soc_codec, delayed_work.work); | 1499 | container_of(work, struct snd_soc_codec, delayed_work.work); |
| 1503 | wm8753_dapm_event(codec, codec->dapm_state); | 1500 | wm8753_set_bias_level(codec, codec->bias_level); |
| 1504 | } | 1501 | } |
| 1505 | 1502 | ||
| 1506 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1503 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) |
| @@ -1512,7 +1509,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 1512 | if (!codec->card) | 1509 | if (!codec->card) |
| 1513 | return 0; | 1510 | return 0; |
| 1514 | 1511 | ||
| 1515 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1512 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1516 | return 0; | 1513 | return 0; |
| 1517 | } | 1514 | } |
| 1518 | 1515 | ||
| @@ -1537,12 +1534,12 @@ static int wm8753_resume(struct platform_device *pdev) | |||
| 1537 | codec->hw_write(codec->control_data, data, 2); | 1534 | codec->hw_write(codec->control_data, data, 2); |
| 1538 | } | 1535 | } |
| 1539 | 1536 | ||
| 1540 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1537 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1541 | 1538 | ||
| 1542 | /* charge wm8753 caps */ | 1539 | /* charge wm8753 caps */ |
| 1543 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | 1540 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
| 1544 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); | 1541 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
| 1545 | codec->dapm_state = SNDRV_CTL_POWER_D0; | 1542 | codec->bias_level = SND_SOC_BIAS_ON; |
| 1546 | schedule_delayed_work(&codec->delayed_work, | 1543 | schedule_delayed_work(&codec->delayed_work, |
| 1547 | msecs_to_jiffies(caps_charge)); | 1544 | msecs_to_jiffies(caps_charge)); |
| 1548 | } | 1545 | } |
| @@ -1563,10 +1560,10 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
| 1563 | codec->owner = THIS_MODULE; | 1560 | codec->owner = THIS_MODULE; |
| 1564 | codec->read = wm8753_read_reg_cache; | 1561 | codec->read = wm8753_read_reg_cache; |
| 1565 | codec->write = wm8753_write; | 1562 | codec->write = wm8753_write; |
| 1566 | codec->dapm_event = wm8753_dapm_event; | 1563 | codec->set_bias_level = wm8753_set_bias_level; |
| 1567 | codec->dai = wm8753_dai; | 1564 | codec->dai = wm8753_dai; |
| 1568 | codec->num_dai = 2; | 1565 | codec->num_dai = 2; |
| 1569 | codec->reg_cache_size = sizeof(wm8753_reg); | 1566 | codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); |
| 1570 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); | 1567 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); |
| 1571 | 1568 | ||
| 1572 | if (codec->reg_cache == NULL) | 1569 | if (codec->reg_cache == NULL) |
| @@ -1584,8 +1581,8 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
| 1584 | } | 1581 | } |
| 1585 | 1582 | ||
| 1586 | /* charge output caps */ | 1583 | /* charge output caps */ |
| 1587 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); | 1584 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
| 1588 | codec->dapm_state = SNDRV_CTL_POWER_D3hot; | 1585 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
| 1589 | schedule_delayed_work(&codec->delayed_work, | 1586 | schedule_delayed_work(&codec->delayed_work, |
| 1590 | msecs_to_jiffies(caps_charge)); | 1587 | msecs_to_jiffies(caps_charge)); |
| 1591 | 1588 | ||
| @@ -1673,13 +1670,13 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
| 1673 | 1670 | ||
| 1674 | ret = i2c_attach_client(i2c); | 1671 | ret = i2c_attach_client(i2c); |
| 1675 | if (ret < 0) { | 1672 | if (ret < 0) { |
| 1676 | err("failed to attach codec at addr %x\n", addr); | 1673 | pr_err("failed to attach codec at addr %x\n", addr); |
| 1677 | goto err; | 1674 | goto err; |
| 1678 | } | 1675 | } |
| 1679 | 1676 | ||
| 1680 | ret = wm8753_init(socdev); | 1677 | ret = wm8753_init(socdev); |
| 1681 | if (ret < 0) { | 1678 | if (ret < 0) { |
| 1682 | err("failed to initialise WM8753\n"); | 1679 | pr_err("failed to initialise WM8753\n"); |
| 1683 | goto err; | 1680 | goto err; |
| 1684 | } | 1681 | } |
| 1685 | 1682 | ||
| @@ -1731,7 +1728,7 @@ static int wm8753_probe(struct platform_device *pdev) | |||
| 1731 | struct wm8753_priv *wm8753; | 1728 | struct wm8753_priv *wm8753; |
| 1732 | int ret = 0; | 1729 | int ret = 0; |
| 1733 | 1730 | ||
| 1734 | info("WM8753 Audio Codec %s", WM8753_VERSION); | 1731 | pr_info("WM8753 Audio Codec %s", WM8753_VERSION); |
| 1735 | 1732 | ||
| 1736 | setup = socdev->codec_data; | 1733 | setup = socdev->codec_data; |
| 1737 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1734 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
| @@ -1792,7 +1789,7 @@ static int wm8753_remove(struct platform_device *pdev) | |||
| 1792 | struct snd_soc_codec *codec = socdev->codec; | 1789 | struct snd_soc_codec *codec = socdev->codec; |
| 1793 | 1790 | ||
| 1794 | if (codec->control_data) | 1791 | if (codec->control_data) |
| 1795 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1792 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1796 | run_delayed_work(&codec->delayed_work); | 1793 | run_delayed_work(&codec->delayed_work); |
| 1797 | snd_soc_free_pcms(socdev); | 1794 | snd_soc_free_pcms(socdev); |
| 1798 | snd_soc_dapm_free(socdev); | 1795 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 95e2a1f53169..44f5f1ff0cc7 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
| @@ -120,7 +120,7 @@ struct wm8753_setup_data { | |||
| 120 | #define WM8753_DAI_HIFI 0 | 120 | #define WM8753_DAI_HIFI 0 |
| 121 | #define WM8753_DAI_VOICE 1 | 121 | #define WM8753_DAI_VOICE 1 |
| 122 | 122 | ||
| 123 | extern struct snd_soc_codec_dai wm8753_dai[2]; | 123 | extern struct snd_soc_dai wm8753_dai[2]; |
| 124 | extern struct snd_soc_codec_device soc_codec_dev_wm8753; | 124 | extern struct snd_soc_codec_device soc_codec_dev_wm8753; |
| 125 | 125 | ||
| 126 | #endif | 126 | #endif |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c new file mode 100644 index 000000000000..3ecce5168e94 --- /dev/null +++ b/sound/soc/codecs/wm8990.c | |||
| @@ -0,0 +1,1626 @@ | |||
| 1 | /* | ||
| 2 | * wm8990.c -- WM8990 ALSA Soc Audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
| 5 | * Author: Liam Girdwood | ||
| 6 | * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/moduleparam.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/pm.h> | ||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <sound/core.h> | ||
| 23 | #include <sound/pcm.h> | ||
| 24 | #include <sound/pcm_params.h> | ||
| 25 | #include <sound/soc.h> | ||
| 26 | #include <sound/soc-dapm.h> | ||
| 27 | #include <sound/initval.h> | ||
| 28 | #include <sound/tlv.h> | ||
| 29 | #include <asm/div64.h> | ||
| 30 | |||
| 31 | #include "wm8990.h" | ||
| 32 | |||
| 33 | #define AUDIO_NAME "wm8990" | ||
| 34 | #define WM8990_VERSION "0.2" | ||
| 35 | |||
| 36 | /* codec private data */ | ||
| 37 | struct wm8990_priv { | ||
| 38 | unsigned int sysclk; | ||
| 39 | unsigned int pcmclk; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * wm8990 register cache. Note that register 0 is not included in the | ||
| 44 | * cache. | ||
| 45 | */ | ||
| 46 | static const u16 wm8990_reg[] = { | ||
| 47 | 0x8990, /* R0 - Reset */ | ||
| 48 | 0x0000, /* R1 - Power Management (1) */ | ||
| 49 | 0x6000, /* R2 - Power Management (2) */ | ||
| 50 | 0x0000, /* R3 - Power Management (3) */ | ||
| 51 | 0x4050, /* R4 - Audio Interface (1) */ | ||
| 52 | 0x4000, /* R5 - Audio Interface (2) */ | ||
| 53 | 0x01C8, /* R6 - Clocking (1) */ | ||
| 54 | 0x0000, /* R7 - Clocking (2) */ | ||
| 55 | 0x0040, /* R8 - Audio Interface (3) */ | ||
| 56 | 0x0040, /* R9 - Audio Interface (4) */ | ||
| 57 | 0x0004, /* R10 - DAC CTRL */ | ||
| 58 | 0x00C0, /* R11 - Left DAC Digital Volume */ | ||
| 59 | 0x00C0, /* R12 - Right DAC Digital Volume */ | ||
| 60 | 0x0000, /* R13 - Digital Side Tone */ | ||
| 61 | 0x0100, /* R14 - ADC CTRL */ | ||
| 62 | 0x00C0, /* R15 - Left ADC Digital Volume */ | ||
| 63 | 0x00C0, /* R16 - Right ADC Digital Volume */ | ||
| 64 | 0x0000, /* R17 */ | ||
| 65 | 0x0000, /* R18 - GPIO CTRL 1 */ | ||
| 66 | 0x1000, /* R19 - GPIO1 & GPIO2 */ | ||
| 67 | 0x1010, /* R20 - GPIO3 & GPIO4 */ | ||
| 68 | 0x1010, /* R21 - GPIO5 & GPIO6 */ | ||
| 69 | 0x8000, /* R22 - GPIOCTRL 2 */ | ||
| 70 | 0x0800, /* R23 - GPIO_POL */ | ||
| 71 | 0x008B, /* R24 - Left Line Input 1&2 Volume */ | ||
| 72 | 0x008B, /* R25 - Left Line Input 3&4 Volume */ | ||
| 73 | 0x008B, /* R26 - Right Line Input 1&2 Volume */ | ||
| 74 | 0x008B, /* R27 - Right Line Input 3&4 Volume */ | ||
| 75 | 0x0000, /* R28 - Left Output Volume */ | ||
| 76 | 0x0000, /* R29 - Right Output Volume */ | ||
| 77 | 0x0066, /* R30 - Line Outputs Volume */ | ||
| 78 | 0x0022, /* R31 - Out3/4 Volume */ | ||
| 79 | 0x0079, /* R32 - Left OPGA Volume */ | ||
| 80 | 0x0079, /* R33 - Right OPGA Volume */ | ||
| 81 | 0x0003, /* R34 - Speaker Volume */ | ||
| 82 | 0x0003, /* R35 - ClassD1 */ | ||
| 83 | 0x0000, /* R36 */ | ||
| 84 | 0x0100, /* R37 - ClassD3 */ | ||
| 85 | 0x0000, /* R38 */ | ||
| 86 | 0x0000, /* R39 - Input Mixer1 */ | ||
| 87 | 0x0000, /* R40 - Input Mixer2 */ | ||
| 88 | 0x0000, /* R41 - Input Mixer3 */ | ||
| 89 | 0x0000, /* R42 - Input Mixer4 */ | ||
| 90 | 0x0000, /* R43 - Input Mixer5 */ | ||
| 91 | 0x0000, /* R44 - Input Mixer6 */ | ||
| 92 | 0x0000, /* R45 - Output Mixer1 */ | ||
| 93 | 0x0000, /* R46 - Output Mixer2 */ | ||
| 94 | 0x0000, /* R47 - Output Mixer3 */ | ||
| 95 | 0x0000, /* R48 - Output Mixer4 */ | ||
| 96 | 0x0000, /* R49 - Output Mixer5 */ | ||
| 97 | 0x0000, /* R50 - Output Mixer6 */ | ||
| 98 | 0x0180, /* R51 - Out3/4 Mixer */ | ||
| 99 | 0x0000, /* R52 - Line Mixer1 */ | ||
| 100 | 0x0000, /* R53 - Line Mixer2 */ | ||
| 101 | 0x0000, /* R54 - Speaker Mixer */ | ||
| 102 | 0x0000, /* R55 - Additional Control */ | ||
| 103 | 0x0000, /* R56 - AntiPOP1 */ | ||
| 104 | 0x0000, /* R57 - AntiPOP2 */ | ||
| 105 | 0x0000, /* R58 - MICBIAS */ | ||
| 106 | 0x0000, /* R59 */ | ||
| 107 | 0x0008, /* R60 - PLL1 */ | ||
| 108 | 0x0031, /* R61 - PLL2 */ | ||
| 109 | 0x0026, /* R62 - PLL3 */ | ||
| 110 | }; | ||
| 111 | |||
| 112 | /* | ||
| 113 | * read wm8990 register cache | ||
| 114 | */ | ||
| 115 | static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, | ||
| 116 | unsigned int reg) | ||
| 117 | { | ||
| 118 | u16 *cache = codec->reg_cache; | ||
| 119 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | ||
| 120 | return cache[reg]; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* | ||
| 124 | * write wm8990 register cache | ||
| 125 | */ | ||
| 126 | static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, | ||
| 127 | unsigned int reg, unsigned int value) | ||
| 128 | { | ||
| 129 | u16 *cache = codec->reg_cache; | ||
| 130 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | ||
| 131 | |||
| 132 | /* Reset register is uncached */ | ||
| 133 | if (reg == 0) | ||
| 134 | return; | ||
| 135 | |||
| 136 | cache[reg] = value; | ||
| 137 | } | ||
| 138 | |||
| 139 | /* | ||
| 140 | * write to the wm8990 register space | ||
| 141 | */ | ||
| 142 | static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, | ||
| 143 | unsigned int value) | ||
| 144 | { | ||
| 145 | u8 data[3]; | ||
| 146 | |||
| 147 | data[0] = reg & 0xFF; | ||
| 148 | data[1] = (value >> 8) & 0xFF; | ||
| 149 | data[2] = value & 0xFF; | ||
| 150 | |||
| 151 | wm8990_write_reg_cache(codec, reg, value); | ||
| 152 | |||
| 153 | if (codec->hw_write(codec->control_data, data, 3) == 2) | ||
| 154 | return 0; | ||
| 155 | else | ||
| 156 | return -EIO; | ||
| 157 | } | ||
| 158 | |||
| 159 | #define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) | ||
| 160 | |||
| 161 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | ||
| 162 | |||
| 163 | static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); | ||
| 164 | |||
| 165 | static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); | ||
| 166 | |||
| 167 | static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); | ||
| 168 | |||
| 169 | static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); | ||
| 170 | |||
| 171 | static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); | ||
| 172 | |||
| 173 | static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); | ||
| 174 | |||
| 175 | static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); | ||
| 176 | |||
| 177 | static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | ||
| 178 | struct snd_ctl_elem_value *ucontrol) | ||
| 179 | { | ||
| 180 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 181 | int reg = kcontrol->private_value & 0xff; | ||
| 182 | int ret; | ||
| 183 | u16 val; | ||
| 184 | |||
| 185 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | ||
| 186 | if (ret < 0) | ||
| 187 | return ret; | ||
| 188 | |||
| 189 | /* now hit the volume update bits (always bit 8) */ | ||
| 190 | val = wm8990_read_reg_cache(codec, reg); | ||
| 191 | return wm8990_write(codec, reg, val | 0x0100); | ||
| 192 | } | ||
| 193 | |||
| 194 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ | ||
| 195 | tlv_array) {\ | ||
| 196 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
| 197 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
| 198 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
| 199 | .tlv.p = (tlv_array), \ | ||
| 200 | .info = snd_soc_info_volsw, \ | ||
| 201 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ | ||
| 202 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
| 203 | |||
| 204 | |||
| 205 | static const char *wm8990_digital_sidetone[] = | ||
| 206 | {"None", "Left ADC", "Right ADC", "Reserved"}; | ||
| 207 | |||
| 208 | static const struct soc_enum wm8990_left_digital_sidetone_enum = | ||
| 209 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | ||
| 210 | WM8990_ADC_TO_DACL_SHIFT, | ||
| 211 | WM8990_ADC_TO_DACL_MASK, | ||
| 212 | wm8990_digital_sidetone); | ||
| 213 | |||
| 214 | static const struct soc_enum wm8990_right_digital_sidetone_enum = | ||
| 215 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | ||
| 216 | WM8990_ADC_TO_DACR_SHIFT, | ||
| 217 | WM8990_ADC_TO_DACR_MASK, | ||
| 218 | wm8990_digital_sidetone); | ||
| 219 | |||
| 220 | static const char *wm8990_adcmode[] = | ||
| 221 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | ||
| 222 | |||
| 223 | static const struct soc_enum wm8990_right_adcmode_enum = | ||
| 224 | SOC_ENUM_SINGLE(WM8990_ADC_CTRL, | ||
| 225 | WM8990_ADC_HPF_CUT_SHIFT, | ||
| 226 | WM8990_ADC_HPF_CUT_MASK, | ||
| 227 | wm8990_adcmode); | ||
| 228 | |||
| 229 | static const struct snd_kcontrol_new wm8990_snd_controls[] = { | ||
| 230 | /* INMIXL */ | ||
| 231 | SOC_SINGLE("LIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L12MNBST_BIT, 1, 0), | ||
| 232 | SOC_SINGLE("LIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L34MNBST_BIT, 1, 0), | ||
| 233 | /* INMIXR */ | ||
| 234 | SOC_SINGLE("RIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R12MNBST_BIT, 1, 0), | ||
| 235 | SOC_SINGLE("RIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R34MNBST_BIT, 1, 0), | ||
| 236 | |||
| 237 | /* LOMIX */ | ||
| 238 | SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
| 239 | WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv), | ||
| 240 | SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
| 241 | WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv), | ||
| 242 | SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
| 243 | WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv), | ||
| 244 | SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
| 245 | WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv), | ||
| 246 | SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
| 247 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
| 248 | SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
| 249 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
| 250 | |||
| 251 | /* ROMIX */ | ||
| 252 | SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
| 253 | WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv), | ||
| 254 | SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
| 255 | WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv), | ||
| 256 | SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
| 257 | WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv), | ||
| 258 | SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
| 259 | WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv), | ||
| 260 | SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
| 261 | WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv), | ||
| 262 | SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
| 263 | WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv), | ||
| 264 | |||
| 265 | /* LOUT */ | ||
| 266 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME, | ||
| 267 | WM8990_LOUTVOL_SHIFT, WM8990_LOUTVOL_MASK, 0, out_pga_tlv), | ||
| 268 | SOC_SINGLE("LOUT ZC", WM8990_LEFT_OUTPUT_VOLUME, WM8990_LOZC_BIT, 1, 0), | ||
| 269 | |||
| 270 | /* ROUT */ | ||
| 271 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME, | ||
| 272 | WM8990_ROUTVOL_SHIFT, WM8990_ROUTVOL_MASK, 0, out_pga_tlv), | ||
| 273 | SOC_SINGLE("ROUT ZC", WM8990_RIGHT_OUTPUT_VOLUME, WM8990_ROZC_BIT, 1, 0), | ||
| 274 | |||
| 275 | /* LOPGA */ | ||
| 276 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME, | ||
| 277 | WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv), | ||
| 278 | SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME, | ||
| 279 | WM8990_LOPGAZC_BIT, 1, 0), | ||
| 280 | |||
| 281 | /* ROPGA */ | ||
| 282 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME, | ||
| 283 | WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv), | ||
| 284 | SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME, | ||
| 285 | WM8990_ROPGAZC_BIT, 1, 0), | ||
| 286 | |||
| 287 | SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
| 288 | WM8990_LONMUTE_BIT, 1, 0), | ||
| 289 | SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
| 290 | WM8990_LOPMUTE_BIT, 1, 0), | ||
| 291 | SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
| 292 | WM8990_LOATTN_BIT, 1, 0), | ||
| 293 | SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
| 294 | WM8990_RONMUTE_BIT, 1, 0), | ||
| 295 | SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
| 296 | WM8990_ROPMUTE_BIT, 1, 0), | ||
| 297 | SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
| 298 | WM8990_ROATTN_BIT, 1, 0), | ||
| 299 | |||
| 300 | SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME, | ||
| 301 | WM8990_OUT3MUTE_BIT, 1, 0), | ||
| 302 | SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME, | ||
| 303 | WM8990_OUT3ATTN_BIT, 1, 0), | ||
| 304 | |||
| 305 | SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME, | ||
| 306 | WM8990_OUT4MUTE_BIT, 1, 0), | ||
| 307 | SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME, | ||
| 308 | WM8990_OUT4ATTN_BIT, 1, 0), | ||
| 309 | |||
| 310 | SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1, | ||
| 311 | WM8990_CDMODE_BIT, 1, 0), | ||
| 312 | |||
| 313 | SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME, | ||
| 314 | WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0), | ||
| 315 | SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3, | ||
| 316 | WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0), | ||
| 317 | SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3, | ||
| 318 | WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0), | ||
| 319 | |||
| 320 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", | ||
| 321 | WM8990_LEFT_DAC_DIGITAL_VOLUME, | ||
| 322 | WM8990_DACL_VOL_SHIFT, | ||
| 323 | WM8990_DACL_VOL_MASK, | ||
| 324 | 0, | ||
| 325 | out_dac_tlv), | ||
| 326 | |||
| 327 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", | ||
| 328 | WM8990_RIGHT_DAC_DIGITAL_VOLUME, | ||
| 329 | WM8990_DACR_VOL_SHIFT, | ||
| 330 | WM8990_DACR_VOL_MASK, | ||
| 331 | 0, | ||
| 332 | out_dac_tlv), | ||
| 333 | |||
| 334 | SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum), | ||
| 335 | SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum), | ||
| 336 | |||
| 337 | SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | ||
| 338 | WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0, | ||
| 339 | out_sidetone_tlv), | ||
| 340 | SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | ||
| 341 | WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0, | ||
| 342 | out_sidetone_tlv), | ||
| 343 | |||
| 344 | SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL, | ||
| 345 | WM8990_ADC_HPF_ENA_BIT, 1, 0), | ||
| 346 | |||
| 347 | SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum), | ||
| 348 | |||
| 349 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", | ||
| 350 | WM8990_LEFT_ADC_DIGITAL_VOLUME, | ||
| 351 | WM8990_ADCL_VOL_SHIFT, | ||
| 352 | WM8990_ADCL_VOL_MASK, | ||
| 353 | 0, | ||
| 354 | in_adc_tlv), | ||
| 355 | |||
| 356 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", | ||
| 357 | WM8990_RIGHT_ADC_DIGITAL_VOLUME, | ||
| 358 | WM8990_ADCR_VOL_SHIFT, | ||
| 359 | WM8990_ADCR_VOL_MASK, | ||
| 360 | 0, | ||
| 361 | in_adc_tlv), | ||
| 362 | |||
| 363 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume", | ||
| 364 | WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
| 365 | WM8990_LIN12VOL_SHIFT, | ||
| 366 | WM8990_LIN12VOL_MASK, | ||
| 367 | 0, | ||
| 368 | in_pga_tlv), | ||
| 369 | |||
| 370 | SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
| 371 | WM8990_LI12ZC_BIT, 1, 0), | ||
| 372 | |||
| 373 | SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
| 374 | WM8990_LI12MUTE_BIT, 1, 0), | ||
| 375 | |||
| 376 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume", | ||
| 377 | WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
| 378 | WM8990_LIN34VOL_SHIFT, | ||
| 379 | WM8990_LIN34VOL_MASK, | ||
| 380 | 0, | ||
| 381 | in_pga_tlv), | ||
| 382 | |||
| 383 | SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
| 384 | WM8990_LI34ZC_BIT, 1, 0), | ||
| 385 | |||
| 386 | SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
| 387 | WM8990_LI34MUTE_BIT, 1, 0), | ||
| 388 | |||
| 389 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume", | ||
| 390 | WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
| 391 | WM8990_RIN12VOL_SHIFT, | ||
| 392 | WM8990_RIN12VOL_MASK, | ||
| 393 | 0, | ||
| 394 | in_pga_tlv), | ||
| 395 | |||
| 396 | SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
| 397 | WM8990_RI12ZC_BIT, 1, 0), | ||
| 398 | |||
| 399 | SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
| 400 | WM8990_RI12MUTE_BIT, 1, 0), | ||
| 401 | |||
| 402 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume", | ||
| 403 | WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
| 404 | WM8990_RIN34VOL_SHIFT, | ||
| 405 | WM8990_RIN34VOL_MASK, | ||
| 406 | 0, | ||
| 407 | in_pga_tlv), | ||
| 408 | |||
| 409 | SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
| 410 | WM8990_RI34ZC_BIT, 1, 0), | ||
| 411 | |||
| 412 | SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
| 413 | WM8990_RI34MUTE_BIT, 1, 0), | ||
| 414 | |||
| 415 | }; | ||
| 416 | |||
| 417 | /* add non dapm controls */ | ||
| 418 | static int wm8990_add_controls(struct snd_soc_codec *codec) | ||
| 419 | { | ||
| 420 | int err, i; | ||
| 421 | |||
| 422 | for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { | ||
| 423 | err = snd_ctl_add(codec->card, | ||
| 424 | snd_soc_cnew(&wm8990_snd_controls[i], codec, | ||
| 425 | NULL)); | ||
| 426 | if (err < 0) | ||
| 427 | return err; | ||
| 428 | } | ||
| 429 | return 0; | ||
| 430 | } | ||
| 431 | |||
| 432 | /* | ||
| 433 | * _DAPM_ Controls | ||
| 434 | */ | ||
| 435 | |||
| 436 | static int inmixer_event(struct snd_soc_dapm_widget *w, | ||
| 437 | struct snd_kcontrol *kcontrol, int event) | ||
| 438 | { | ||
| 439 | u16 reg, fakepower; | ||
| 440 | |||
| 441 | reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); | ||
| 442 | fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); | ||
| 443 | |||
| 444 | if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | | ||
| 445 | (1 << WM8990_AINLMUX_PWR_BIT))) { | ||
| 446 | reg |= WM8990_AINL_ENA; | ||
| 447 | } else { | ||
| 448 | reg &= ~WM8990_AINL_ENA; | ||
| 449 | } | ||
| 450 | |||
| 451 | if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | | ||
| 452 | (1 << WM8990_AINRMUX_PWR_BIT))) { | ||
| 453 | reg |= WM8990_AINR_ENA; | ||
| 454 | } else { | ||
| 455 | reg &= ~WM8990_AINL_ENA; | ||
| 456 | } | ||
| 457 | wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
| 458 | |||
| 459 | return 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | static int outmixer_event(struct snd_soc_dapm_widget *w, | ||
| 463 | struct snd_kcontrol *kcontrol, int event) | ||
| 464 | { | ||
| 465 | u32 reg_shift = kcontrol->private_value & 0xfff; | ||
| 466 | int ret = 0; | ||
| 467 | u16 reg; | ||
| 468 | |||
| 469 | switch (reg_shift) { | ||
| 470 | case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : | ||
| 471 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); | ||
| 472 | if (reg & WM8990_LDLO) { | ||
| 473 | printk(KERN_WARNING | ||
| 474 | "Cannot set as Output Mixer 1 LDLO Set\n"); | ||
| 475 | ret = -1; | ||
| 476 | } | ||
| 477 | break; | ||
| 478 | case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): | ||
| 479 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); | ||
| 480 | if (reg & WM8990_RDRO) { | ||
| 481 | printk(KERN_WARNING | ||
| 482 | "Cannot set as Output Mixer 2 RDRO Set\n"); | ||
| 483 | ret = -1; | ||
| 484 | } | ||
| 485 | break; | ||
| 486 | case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): | ||
| 487 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | ||
| 488 | if (reg & WM8990_LDSPK) { | ||
| 489 | printk(KERN_WARNING | ||
| 490 | "Cannot set as Speaker Mixer LDSPK Set\n"); | ||
| 491 | ret = -1; | ||
| 492 | } | ||
| 493 | break; | ||
| 494 | case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): | ||
| 495 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | ||
| 496 | if (reg & WM8990_RDSPK) { | ||
| 497 | printk(KERN_WARNING | ||
| 498 | "Cannot set as Speaker Mixer RDSPK Set\n"); | ||
| 499 | ret = -1; | ||
| 500 | } | ||
| 501 | break; | ||
| 502 | } | ||
| 503 | |||
| 504 | return ret; | ||
| 505 | } | ||
| 506 | |||
| 507 | /* INMIX dB values */ | ||
| 508 | static const unsigned int in_mix_tlv[] = { | ||
| 509 | TLV_DB_RANGE_HEAD(1), | ||
| 510 | 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), | ||
| 511 | }; | ||
| 512 | |||
| 513 | /* Left In PGA Connections */ | ||
| 514 | static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { | ||
| 515 | SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0), | ||
| 516 | SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0), | ||
| 517 | }; | ||
| 518 | |||
| 519 | static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = { | ||
| 520 | SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0), | ||
| 521 | SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0), | ||
| 522 | }; | ||
| 523 | |||
| 524 | /* Right In PGA Connections */ | ||
| 525 | static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = { | ||
| 526 | SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0), | ||
| 527 | SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0), | ||
| 528 | }; | ||
| 529 | |||
| 530 | static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = { | ||
| 531 | SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0), | ||
| 532 | SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0), | ||
| 533 | }; | ||
| 534 | |||
| 535 | /* INMIXL */ | ||
| 536 | static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = { | ||
| 537 | SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3, | ||
| 538 | WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv), | ||
| 539 | SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT, | ||
| 540 | 7, 0, in_mix_tlv), | ||
| 541 | SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | ||
| 542 | 1, 0), | ||
| 543 | SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | ||
| 544 | 1, 0), | ||
| 545 | }; | ||
| 546 | |||
| 547 | /* INMIXR */ | ||
| 548 | static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = { | ||
| 549 | SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4, | ||
| 550 | WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv), | ||
| 551 | SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT, | ||
| 552 | 7, 0, in_mix_tlv), | ||
| 553 | SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | ||
| 554 | 1, 0), | ||
| 555 | SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | ||
| 556 | 1, 0), | ||
| 557 | }; | ||
| 558 | |||
| 559 | /* AINLMUX */ | ||
| 560 | static const char *wm8990_ainlmux[] = | ||
| 561 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | ||
| 562 | |||
| 563 | static const struct soc_enum wm8990_ainlmux_enum = | ||
| 564 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, | ||
| 565 | ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); | ||
| 566 | |||
| 567 | static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = | ||
| 568 | SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); | ||
| 569 | |||
| 570 | /* DIFFINL */ | ||
| 571 | |||
| 572 | /* AINRMUX */ | ||
| 573 | static const char *wm8990_ainrmux[] = | ||
| 574 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | ||
| 575 | |||
| 576 | static const struct soc_enum wm8990_ainrmux_enum = | ||
| 577 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, | ||
| 578 | ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); | ||
| 579 | |||
| 580 | static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = | ||
| 581 | SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); | ||
| 582 | |||
| 583 | /* RXVOICE */ | ||
| 584 | static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { | ||
| 585 | SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, | ||
| 586 | WM8990_LR4BVOL_MASK, 0, in_mix_tlv), | ||
| 587 | SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, | ||
| 588 | WM8990_RL4BVOL_MASK, 0, in_mix_tlv), | ||
| 589 | }; | ||
| 590 | |||
| 591 | /* LOMIX */ | ||
| 592 | static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { | ||
| 593 | SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
| 594 | WM8990_LRBLO_BIT, 1, 0), | ||
| 595 | SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
| 596 | WM8990_LLBLO_BIT, 1, 0), | ||
| 597 | SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
| 598 | WM8990_LRI3LO_BIT, 1, 0), | ||
| 599 | SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
| 600 | WM8990_LLI3LO_BIT, 1, 0), | ||
| 601 | SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
| 602 | WM8990_LR12LO_BIT, 1, 0), | ||
| 603 | SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
| 604 | WM8990_LL12LO_BIT, 1, 0), | ||
| 605 | SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1, | ||
| 606 | WM8990_LDLO_BIT, 1, 0), | ||
| 607 | }; | ||
| 608 | |||
| 609 | /* ROMIX */ | ||
| 610 | static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = { | ||
| 611 | SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
| 612 | WM8990_RLBRO_BIT, 1, 0), | ||
| 613 | SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
| 614 | WM8990_RRBRO_BIT, 1, 0), | ||
| 615 | SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
| 616 | WM8990_RLI3RO_BIT, 1, 0), | ||
| 617 | SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
| 618 | WM8990_RRI3RO_BIT, 1, 0), | ||
| 619 | SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
| 620 | WM8990_RL12RO_BIT, 1, 0), | ||
| 621 | SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
| 622 | WM8990_RR12RO_BIT, 1, 0), | ||
| 623 | SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2, | ||
| 624 | WM8990_RDRO_BIT, 1, 0), | ||
| 625 | }; | ||
| 626 | |||
| 627 | /* LONMIX */ | ||
| 628 | static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = { | ||
| 629 | SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
| 630 | WM8990_LLOPGALON_BIT, 1, 0), | ||
| 631 | SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
| 632 | WM8990_LROPGALON_BIT, 1, 0), | ||
| 633 | SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1, | ||
| 634 | WM8990_LOPLON_BIT, 1, 0), | ||
| 635 | }; | ||
| 636 | |||
| 637 | /* LOPMIX */ | ||
| 638 | static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = { | ||
| 639 | SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1, | ||
| 640 | WM8990_LR12LOP_BIT, 1, 0), | ||
| 641 | SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1, | ||
| 642 | WM8990_LL12LOP_BIT, 1, 0), | ||
| 643 | SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
| 644 | WM8990_LLOPGALOP_BIT, 1, 0), | ||
| 645 | }; | ||
| 646 | |||
| 647 | /* RONMIX */ | ||
| 648 | static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = { | ||
| 649 | SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
| 650 | WM8990_RROPGARON_BIT, 1, 0), | ||
| 651 | SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
| 652 | WM8990_RLOPGARON_BIT, 1, 0), | ||
| 653 | SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2, | ||
| 654 | WM8990_ROPRON_BIT, 1, 0), | ||
| 655 | }; | ||
| 656 | |||
| 657 | /* ROPMIX */ | ||
| 658 | static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = { | ||
| 659 | SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2, | ||
| 660 | WM8990_RL12ROP_BIT, 1, 0), | ||
| 661 | SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2, | ||
| 662 | WM8990_RR12ROP_BIT, 1, 0), | ||
| 663 | SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
| 664 | WM8990_RROPGAROP_BIT, 1, 0), | ||
| 665 | }; | ||
| 666 | |||
| 667 | /* OUT3MIX */ | ||
| 668 | static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = { | ||
| 669 | SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | ||
| 670 | WM8990_LI4O3_BIT, 1, 0), | ||
| 671 | SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER, | ||
| 672 | WM8990_LPGAO3_BIT, 1, 0), | ||
| 673 | }; | ||
| 674 | |||
| 675 | /* OUT4MIX */ | ||
| 676 | static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = { | ||
| 677 | SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER, | ||
| 678 | WM8990_RPGAO4_BIT, 1, 0), | ||
| 679 | SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | ||
| 680 | WM8990_RI4O4_BIT, 1, 0), | ||
| 681 | }; | ||
| 682 | |||
| 683 | /* SPKMIX */ | ||
| 684 | static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = { | ||
| 685 | SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | ||
| 686 | WM8990_LI2SPK_BIT, 1, 0), | ||
| 687 | SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER, | ||
| 688 | WM8990_LB2SPK_BIT, 1, 0), | ||
| 689 | SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER, | ||
| 690 | WM8990_LOPGASPK_BIT, 1, 0), | ||
| 691 | SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER, | ||
| 692 | WM8990_LDSPK_BIT, 1, 0), | ||
| 693 | SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER, | ||
| 694 | WM8990_RDSPK_BIT, 1, 0), | ||
| 695 | SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER, | ||
| 696 | WM8990_ROPGASPK_BIT, 1, 0), | ||
| 697 | SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER, | ||
| 698 | WM8990_RL12ROP_BIT, 1, 0), | ||
| 699 | SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | ||
| 700 | WM8990_RI2SPK_BIT, 1, 0), | ||
| 701 | }; | ||
| 702 | |||
| 703 | static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = { | ||
| 704 | /* Input Side */ | ||
| 705 | /* Input Lines */ | ||
| 706 | SND_SOC_DAPM_INPUT("LIN1"), | ||
| 707 | SND_SOC_DAPM_INPUT("LIN2"), | ||
| 708 | SND_SOC_DAPM_INPUT("LIN3"), | ||
| 709 | SND_SOC_DAPM_INPUT("LIN4/RXN"), | ||
| 710 | SND_SOC_DAPM_INPUT("RIN3"), | ||
| 711 | SND_SOC_DAPM_INPUT("RIN4/RXP"), | ||
| 712 | SND_SOC_DAPM_INPUT("RIN1"), | ||
| 713 | SND_SOC_DAPM_INPUT("RIN2"), | ||
| 714 | SND_SOC_DAPM_INPUT("Internal ADC Source"), | ||
| 715 | |||
| 716 | /* DACs */ | ||
| 717 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, | ||
| 718 | WM8990_ADCL_ENA_BIT, 0), | ||
| 719 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2, | ||
| 720 | WM8990_ADCR_ENA_BIT, 0), | ||
| 721 | |||
| 722 | /* Input PGAs */ | ||
| 723 | SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT, | ||
| 724 | 0, &wm8990_dapm_lin12_pga_controls[0], | ||
| 725 | ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)), | ||
| 726 | SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT, | ||
| 727 | 0, &wm8990_dapm_lin34_pga_controls[0], | ||
| 728 | ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)), | ||
| 729 | SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT, | ||
| 730 | 0, &wm8990_dapm_rin12_pga_controls[0], | ||
| 731 | ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)), | ||
| 732 | SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT, | ||
| 733 | 0, &wm8990_dapm_rin34_pga_controls[0], | ||
| 734 | ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), | ||
| 735 | |||
| 736 | /* INMIXL */ | ||
| 737 | SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, | ||
| 738 | &wm8990_dapm_inmixl_controls[0], | ||
| 739 | ARRAY_SIZE(wm8990_dapm_inmixl_controls), | ||
| 740 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
| 741 | |||
| 742 | /* AINLMUX */ | ||
| 743 | SND_SOC_DAPM_MUX_E("AILNMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, | ||
| 744 | &wm8990_dapm_ainlmux_controls, inmixer_event, | ||
| 745 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
| 746 | |||
| 747 | /* INMIXR */ | ||
| 748 | SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, | ||
| 749 | &wm8990_dapm_inmixr_controls[0], | ||
| 750 | ARRAY_SIZE(wm8990_dapm_inmixr_controls), | ||
| 751 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
| 752 | |||
| 753 | /* AINRMUX */ | ||
| 754 | SND_SOC_DAPM_MUX_E("AIRNMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, | ||
| 755 | &wm8990_dapm_ainrmux_controls, inmixer_event, | ||
| 756 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
| 757 | |||
| 758 | /* Output Side */ | ||
| 759 | /* DACs */ | ||
| 760 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3, | ||
| 761 | WM8990_DACL_ENA_BIT, 0), | ||
| 762 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3, | ||
| 763 | WM8990_DACR_ENA_BIT, 0), | ||
| 764 | |||
| 765 | /* LOMIX */ | ||
| 766 | SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT, | ||
| 767 | 0, &wm8990_dapm_lomix_controls[0], | ||
| 768 | ARRAY_SIZE(wm8990_dapm_lomix_controls), | ||
| 769 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
| 770 | |||
| 771 | /* LONMIX */ | ||
| 772 | SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0, | ||
| 773 | &wm8990_dapm_lonmix_controls[0], | ||
| 774 | ARRAY_SIZE(wm8990_dapm_lonmix_controls)), | ||
| 775 | |||
| 776 | /* LOPMIX */ | ||
| 777 | SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0, | ||
| 778 | &wm8990_dapm_lopmix_controls[0], | ||
| 779 | ARRAY_SIZE(wm8990_dapm_lopmix_controls)), | ||
| 780 | |||
| 781 | /* OUT3MIX */ | ||
| 782 | SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0, | ||
| 783 | &wm8990_dapm_out3mix_controls[0], | ||
| 784 | ARRAY_SIZE(wm8990_dapm_out3mix_controls)), | ||
| 785 | |||
| 786 | /* SPKMIX */ | ||
| 787 | SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0, | ||
| 788 | &wm8990_dapm_spkmix_controls[0], | ||
| 789 | ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event, | ||
| 790 | SND_SOC_DAPM_PRE_REG), | ||
| 791 | |||
| 792 | /* OUT4MIX */ | ||
| 793 | SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0, | ||
| 794 | &wm8990_dapm_out4mix_controls[0], | ||
| 795 | ARRAY_SIZE(wm8990_dapm_out4mix_controls)), | ||
| 796 | |||
| 797 | /* ROPMIX */ | ||
| 798 | SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0, | ||
| 799 | &wm8990_dapm_ropmix_controls[0], | ||
| 800 | ARRAY_SIZE(wm8990_dapm_ropmix_controls)), | ||
| 801 | |||
| 802 | /* RONMIX */ | ||
| 803 | SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0, | ||
| 804 | &wm8990_dapm_ronmix_controls[0], | ||
| 805 | ARRAY_SIZE(wm8990_dapm_ronmix_controls)), | ||
| 806 | |||
| 807 | /* ROMIX */ | ||
| 808 | SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT, | ||
| 809 | 0, &wm8990_dapm_romix_controls[0], | ||
| 810 | ARRAY_SIZE(wm8990_dapm_romix_controls), | ||
| 811 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
| 812 | |||
| 813 | /* LOUT PGA */ | ||
| 814 | SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0, | ||
| 815 | NULL, 0), | ||
| 816 | |||
| 817 | /* ROUT PGA */ | ||
| 818 | SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0, | ||
| 819 | NULL, 0), | ||
| 820 | |||
| 821 | /* LOPGA */ | ||
| 822 | SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0, | ||
| 823 | NULL, 0), | ||
| 824 | |||
| 825 | /* ROPGA */ | ||
| 826 | SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0, | ||
| 827 | NULL, 0), | ||
| 828 | |||
| 829 | /* MICBIAS */ | ||
| 830 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1, | ||
| 831 | WM8990_MICBIAS_ENA_BIT, 0), | ||
| 832 | |||
| 833 | SND_SOC_DAPM_OUTPUT("LON"), | ||
| 834 | SND_SOC_DAPM_OUTPUT("LOP"), | ||
| 835 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
| 836 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
| 837 | SND_SOC_DAPM_OUTPUT("SPKN"), | ||
| 838 | SND_SOC_DAPM_OUTPUT("SPKP"), | ||
| 839 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
| 840 | SND_SOC_DAPM_OUTPUT("OUT4"), | ||
| 841 | SND_SOC_DAPM_OUTPUT("ROP"), | ||
| 842 | SND_SOC_DAPM_OUTPUT("RON"), | ||
| 843 | |||
| 844 | SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), | ||
| 845 | }; | ||
| 846 | |||
| 847 | static const struct snd_soc_dapm_route audio_map[] = { | ||
| 848 | /* Make DACs turn on when playing even if not mixed into any outputs */ | ||
| 849 | {"Internal DAC Sink", NULL, "Left DAC"}, | ||
| 850 | {"Internal DAC Sink", NULL, "Right DAC"}, | ||
| 851 | |||
| 852 | /* Make ADCs turn on when recording even if not mixed from any inputs */ | ||
| 853 | {"Left ADC", NULL, "Internal ADC Source"}, | ||
| 854 | {"Right ADC", NULL, "Internal ADC Source"}, | ||
| 855 | |||
| 856 | /* Input Side */ | ||
| 857 | /* LIN12 PGA */ | ||
| 858 | {"LIN12 PGA", "LIN1 Switch", "LIN1"}, | ||
| 859 | {"LIN12 PGA", "LIN2 Switch", "LIN2"}, | ||
| 860 | /* LIN34 PGA */ | ||
| 861 | {"LIN34 PGA", "LIN3 Switch", "LIN3"}, | ||
| 862 | {"LIN34 PGA", "LIN4 Switch", "LIN4"}, | ||
| 863 | /* INMIXL */ | ||
| 864 | {"INMIXL", "Record Left Volume", "LOMIX"}, | ||
| 865 | {"INMIXL", "LIN2 Volume", "LIN2"}, | ||
| 866 | {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, | ||
| 867 | {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, | ||
| 868 | /* AILNMUX */ | ||
| 869 | {"AILNMUX", "INMIXL Mix", "INMIXL"}, | ||
| 870 | {"AILNMUX", "DIFFINL Mix", "LIN12PGA"}, | ||
| 871 | {"AILNMUX", "DIFFINL Mix", "LIN34PGA"}, | ||
| 872 | {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, | ||
| 873 | {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
| 874 | /* ADC */ | ||
| 875 | {"Left ADC", NULL, "AILNMUX"}, | ||
| 876 | |||
| 877 | /* RIN12 PGA */ | ||
| 878 | {"RIN12 PGA", "RIN1 Switch", "RIN1"}, | ||
| 879 | {"RIN12 PGA", "RIN2 Switch", "RIN2"}, | ||
| 880 | /* RIN34 PGA */ | ||
| 881 | {"RIN34 PGA", "RIN3 Switch", "RIN3"}, | ||
| 882 | {"RIN34 PGA", "RIN4 Switch", "RIN4"}, | ||
| 883 | /* INMIXL */ | ||
| 884 | {"INMIXR", "Record Right Volume", "ROMIX"}, | ||
| 885 | {"INMIXR", "RIN2 Volume", "RIN2"}, | ||
| 886 | {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, | ||
| 887 | {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, | ||
| 888 | /* AIRNMUX */ | ||
| 889 | {"AIRNMUX", "INMIXR Mix", "INMIXR"}, | ||
| 890 | {"AIRNMUX", "DIFFINR Mix", "RIN12PGA"}, | ||
| 891 | {"AIRNMUX", "DIFFINR Mix", "RIN34PGA"}, | ||
| 892 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXN"}, | ||
| 893 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
| 894 | /* ADC */ | ||
| 895 | {"Right ADC", NULL, "AIRNMUX"}, | ||
| 896 | |||
| 897 | /* LOMIX */ | ||
| 898 | {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, | ||
| 899 | {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, | ||
| 900 | {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
| 901 | {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
| 902 | {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
| 903 | {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
| 904 | {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, | ||
| 905 | |||
| 906 | /* ROMIX */ | ||
| 907 | {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, | ||
| 908 | {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, | ||
| 909 | {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
| 910 | {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
| 911 | {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
| 912 | {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
| 913 | {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, | ||
| 914 | |||
| 915 | /* SPKMIX */ | ||
| 916 | {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, | ||
| 917 | {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, | ||
| 918 | {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"}, | ||
| 919 | {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"}, | ||
| 920 | {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, | ||
| 921 | {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, | ||
| 922 | {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, | ||
| 923 | {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"}, | ||
| 924 | |||
| 925 | /* LONMIX */ | ||
| 926 | {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
| 927 | {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
| 928 | {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, | ||
| 929 | |||
| 930 | /* LOPMIX */ | ||
| 931 | {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
| 932 | {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
| 933 | {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, | ||
| 934 | |||
| 935 | /* OUT3MIX */ | ||
| 936 | {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXP"}, | ||
| 937 | {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, | ||
| 938 | |||
| 939 | /* OUT4MIX */ | ||
| 940 | {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, | ||
| 941 | {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, | ||
| 942 | |||
| 943 | /* RONMIX */ | ||
| 944 | {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
| 945 | {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
| 946 | {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, | ||
| 947 | |||
| 948 | /* ROPMIX */ | ||
| 949 | {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
| 950 | {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
| 951 | {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, | ||
| 952 | |||
| 953 | /* Out Mixer PGAs */ | ||
| 954 | {"LOPGA", NULL, "LOMIX"}, | ||
| 955 | {"ROPGA", NULL, "ROMIX"}, | ||
| 956 | |||
| 957 | {"LOUT PGA", NULL, "LOMIX"}, | ||
| 958 | {"ROUT PGA", NULL, "ROMIX"}, | ||
| 959 | |||
| 960 | /* Output Pins */ | ||
| 961 | {"LON", NULL, "LONMIX"}, | ||
| 962 | {"LOP", NULL, "LOPMIX"}, | ||
| 963 | {"OUT", NULL, "OUT3MIX"}, | ||
| 964 | {"LOUT", NULL, "LOUT PGA"}, | ||
| 965 | {"SPKN", NULL, "SPKMIX"}, | ||
| 966 | {"ROUT", NULL, "ROUT PGA"}, | ||
| 967 | {"OUT4", NULL, "OUT4MIX"}, | ||
| 968 | {"ROP", NULL, "ROPMIX"}, | ||
| 969 | {"RON", NULL, "RONMIX"}, | ||
| 970 | }; | ||
| 971 | |||
| 972 | static int wm8990_add_widgets(struct snd_soc_codec *codec) | ||
| 973 | { | ||
| 974 | snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets, | ||
| 975 | ARRAY_SIZE(wm8990_dapm_widgets)); | ||
| 976 | |||
| 977 | /* set up the WM8990 audio map */ | ||
| 978 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
| 979 | |||
| 980 | snd_soc_dapm_new_widgets(codec); | ||
| 981 | return 0; | ||
| 982 | } | ||
| 983 | |||
| 984 | /* PLL divisors */ | ||
| 985 | struct _pll_div { | ||
| 986 | u32 div2; | ||
| 987 | u32 n; | ||
| 988 | u32 k; | ||
| 989 | }; | ||
| 990 | |||
| 991 | /* The size in bits of the pll divide multiplied by 10 | ||
| 992 | * to allow rounding later */ | ||
| 993 | #define FIXED_PLL_SIZE ((1 << 16) * 10) | ||
| 994 | |||
| 995 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, | ||
| 996 | unsigned int source) | ||
| 997 | { | ||
| 998 | u64 Kpart; | ||
| 999 | unsigned int K, Ndiv, Nmod; | ||
| 1000 | |||
| 1001 | |||
| 1002 | Ndiv = target / source; | ||
| 1003 | if (Ndiv < 6) { | ||
| 1004 | source >>= 1; | ||
| 1005 | pll_div->div2 = 1; | ||
| 1006 | Ndiv = target / source; | ||
| 1007 | } else | ||
| 1008 | pll_div->div2 = 0; | ||
| 1009 | |||
| 1010 | if ((Ndiv < 6) || (Ndiv > 12)) | ||
| 1011 | printk(KERN_WARNING | ||
| 1012 | "WM8990 N value outwith recommended range! N = %d\n", Ndiv); | ||
| 1013 | |||
| 1014 | pll_div->n = Ndiv; | ||
| 1015 | Nmod = target % source; | ||
| 1016 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
| 1017 | |||
| 1018 | do_div(Kpart, source); | ||
| 1019 | |||
| 1020 | K = Kpart & 0xFFFFFFFF; | ||
| 1021 | |||
| 1022 | /* Check if we need to round */ | ||
| 1023 | if ((K % 10) >= 5) | ||
| 1024 | K += 5; | ||
| 1025 | |||
| 1026 | /* Move down to proper range now rounding is done */ | ||
| 1027 | K /= 10; | ||
| 1028 | |||
| 1029 | pll_div->k = K; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
| 1033 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
| 1034 | { | ||
| 1035 | u16 reg; | ||
| 1036 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 1037 | struct _pll_div pll_div; | ||
| 1038 | |||
| 1039 | if (freq_in && freq_out) { | ||
| 1040 | pll_factors(&pll_div, freq_out * 4, freq_in); | ||
| 1041 | |||
| 1042 | /* Turn on PLL */ | ||
| 1043 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
| 1044 | reg |= WM8990_PLL_ENA; | ||
| 1045 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
| 1046 | |||
| 1047 | /* sysclk comes from PLL */ | ||
| 1048 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); | ||
| 1049 | wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); | ||
| 1050 | |||
| 1051 | /* set up N , fractional mode and pre-divisor if neccessary */ | ||
| 1052 | wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | | ||
| 1053 | (pll_div.div2?WM8990_PRESCALE:0)); | ||
| 1054 | wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); | ||
| 1055 | wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); | ||
| 1056 | } else { | ||
| 1057 | /* Turn on PLL */ | ||
| 1058 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
| 1059 | reg &= ~WM8990_PLL_ENA; | ||
| 1060 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
| 1061 | } | ||
| 1062 | return 0; | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | /* | ||
| 1066 | * Clock after PLL and dividers | ||
| 1067 | */ | ||
| 1068 | static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
| 1069 | int clk_id, unsigned int freq, int dir) | ||
| 1070 | { | ||
| 1071 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 1072 | struct wm8990_priv *wm8990 = codec->private_data; | ||
| 1073 | |||
| 1074 | wm8990->sysclk = freq; | ||
| 1075 | return 0; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | /* | ||
| 1079 | * Set's ADC and Voice DAC format. | ||
| 1080 | */ | ||
| 1081 | static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
| 1082 | unsigned int fmt) | ||
| 1083 | { | ||
| 1084 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 1085 | u16 audio1, audio3; | ||
| 1086 | |||
| 1087 | audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | ||
| 1088 | audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); | ||
| 1089 | |||
| 1090 | /* set master/slave audio interface */ | ||
| 1091 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 1092 | case SND_SOC_DAIFMT_CBS_CFS: | ||
| 1093 | audio3 &= ~WM8990_AIF_MSTR1; | ||
| 1094 | break; | ||
| 1095 | case SND_SOC_DAIFMT_CBM_CFM: | ||
| 1096 | audio3 |= WM8990_AIF_MSTR1; | ||
| 1097 | break; | ||
| 1098 | default: | ||
| 1099 | return -EINVAL; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | audio1 &= ~WM8990_AIF_FMT_MASK; | ||
| 1103 | |||
| 1104 | /* interface format */ | ||
| 1105 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 1106 | case SND_SOC_DAIFMT_I2S: | ||
| 1107 | audio1 |= WM8990_AIF_TMF_I2S; | ||
| 1108 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
| 1109 | break; | ||
| 1110 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 1111 | audio1 |= WM8990_AIF_TMF_RIGHTJ; | ||
| 1112 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
| 1113 | break; | ||
| 1114 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 1115 | audio1 |= WM8990_AIF_TMF_LEFTJ; | ||
| 1116 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
| 1117 | break; | ||
| 1118 | case SND_SOC_DAIFMT_DSP_A: | ||
| 1119 | audio1 |= WM8990_AIF_TMF_DSP; | ||
| 1120 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
| 1121 | break; | ||
| 1122 | case SND_SOC_DAIFMT_DSP_B: | ||
| 1123 | audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV; | ||
| 1124 | break; | ||
| 1125 | default: | ||
| 1126 | return -EINVAL; | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | ||
| 1130 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); | ||
| 1131 | return 0; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
| 1135 | int div_id, int div) | ||
| 1136 | { | ||
| 1137 | struct snd_soc_codec *codec = codec_dai->codec; | ||
| 1138 | u16 reg; | ||
| 1139 | |||
| 1140 | switch (div_id) { | ||
| 1141 | case WM8990_MCLK_DIV: | ||
| 1142 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
| 1143 | ~WM8990_MCLK_DIV_MASK; | ||
| 1144 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
| 1145 | break; | ||
| 1146 | case WM8990_DACCLK_DIV: | ||
| 1147 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
| 1148 | ~WM8990_DAC_CLKDIV_MASK; | ||
| 1149 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
| 1150 | break; | ||
| 1151 | case WM8990_ADCCLK_DIV: | ||
| 1152 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
| 1153 | ~WM8990_ADC_CLKDIV_MASK; | ||
| 1154 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
| 1155 | break; | ||
| 1156 | case WM8990_BCLK_DIV: | ||
| 1157 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & | ||
| 1158 | ~WM8990_BCLK_DIV_MASK; | ||
| 1159 | wm8990_write(codec, WM8990_CLOCKING_1, reg | div); | ||
| 1160 | break; | ||
| 1161 | default: | ||
| 1162 | return -EINVAL; | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | return 0; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | /* | ||
| 1169 | * Set PCM DAI bit size and sample rate. | ||
| 1170 | */ | ||
| 1171 | static int wm8990_hw_params(struct snd_pcm_substream *substream, | ||
| 1172 | struct snd_pcm_hw_params *params) | ||
| 1173 | { | ||
| 1174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 1175 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 1176 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1177 | u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | ||
| 1178 | |||
| 1179 | audio1 &= ~WM8990_AIF_WL_MASK; | ||
| 1180 | /* bit size */ | ||
| 1181 | switch (params_format(params)) { | ||
| 1182 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 1183 | break; | ||
| 1184 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
| 1185 | audio1 |= WM8990_AIF_WL_20BITS; | ||
| 1186 | break; | ||
| 1187 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 1188 | audio1 |= WM8990_AIF_WL_24BITS; | ||
| 1189 | break; | ||
| 1190 | case SNDRV_PCM_FORMAT_S32_LE: | ||
| 1191 | audio1 |= WM8990_AIF_WL_32BITS; | ||
| 1192 | break; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | ||
| 1196 | return 0; | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | static int wm8990_mute(struct snd_soc_dai *dai, int mute) | ||
| 1200 | { | ||
| 1201 | struct snd_soc_codec *codec = dai->codec; | ||
| 1202 | u16 val; | ||
| 1203 | |||
| 1204 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; | ||
| 1205 | |||
| 1206 | if (mute) | ||
| 1207 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | ||
| 1208 | else | ||
| 1209 | wm8990_write(codec, WM8990_DAC_CTRL, val); | ||
| 1210 | |||
| 1211 | return 0; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | static int wm8990_set_bias_level(struct snd_soc_codec *codec, | ||
| 1215 | enum snd_soc_bias_level level) | ||
| 1216 | { | ||
| 1217 | u16 val; | ||
| 1218 | |||
| 1219 | switch (level) { | ||
| 1220 | case SND_SOC_BIAS_ON: | ||
| 1221 | break; | ||
| 1222 | case SND_SOC_BIAS_PREPARE: | ||
| 1223 | break; | ||
| 1224 | case SND_SOC_BIAS_STANDBY: | ||
| 1225 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
| 1226 | /* Enable all output discharge bits */ | ||
| 1227 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | ||
| 1228 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | ||
| 1229 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | ||
| 1230 | WM8990_DIS_ROUT); | ||
| 1231 | |||
| 1232 | /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ | ||
| 1233 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
| 1234 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
| 1235 | WM8990_VMIDTOG); | ||
| 1236 | |||
| 1237 | /* Delay to allow output caps to discharge */ | ||
| 1238 | msleep(msecs_to_jiffies(300)); | ||
| 1239 | |||
| 1240 | /* Disable VMIDTOG */ | ||
| 1241 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
| 1242 | WM8990_BUFDCOPEN | WM8990_POBCTRL); | ||
| 1243 | |||
| 1244 | /* disable all output discharge bits */ | ||
| 1245 | wm8990_write(codec, WM8990_ANTIPOP1, 0); | ||
| 1246 | |||
| 1247 | /* Enable outputs */ | ||
| 1248 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); | ||
| 1249 | |||
| 1250 | msleep(msecs_to_jiffies(50)); | ||
| 1251 | |||
| 1252 | /* Enable VMID at 2x50k */ | ||
| 1253 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); | ||
| 1254 | |||
| 1255 | msleep(msecs_to_jiffies(100)); | ||
| 1256 | |||
| 1257 | /* Enable VREF */ | ||
| 1258 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | ||
| 1259 | |||
| 1260 | msleep(msecs_to_jiffies(600)); | ||
| 1261 | |||
| 1262 | /* Enable BUFIOEN */ | ||
| 1263 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
| 1264 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
| 1265 | WM8990_BUFIOEN); | ||
| 1266 | |||
| 1267 | /* Disable outputs */ | ||
| 1268 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); | ||
| 1269 | |||
| 1270 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
| 1271 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); | ||
| 1272 | } else { | ||
| 1273 | /* ON -> standby */ | ||
| 1274 | |||
| 1275 | } | ||
| 1276 | break; | ||
| 1277 | |||
| 1278 | case SND_SOC_BIAS_OFF: | ||
| 1279 | /* Enable POBCTRL and SOFT_ST */ | ||
| 1280 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
| 1281 | WM8990_POBCTRL | WM8990_BUFIOEN); | ||
| 1282 | |||
| 1283 | /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
| 1284 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
| 1285 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
| 1286 | WM8990_BUFIOEN); | ||
| 1287 | |||
| 1288 | /* mute DAC */ | ||
| 1289 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); | ||
| 1290 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | ||
| 1291 | |||
| 1292 | /* Enable any disabled outputs */ | ||
| 1293 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | ||
| 1294 | |||
| 1295 | /* Disable VMID */ | ||
| 1296 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); | ||
| 1297 | |||
| 1298 | msleep(msecs_to_jiffies(300)); | ||
| 1299 | |||
| 1300 | /* Enable all output discharge bits */ | ||
| 1301 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | ||
| 1302 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | ||
| 1303 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | ||
| 1304 | WM8990_DIS_ROUT); | ||
| 1305 | |||
| 1306 | /* Disable VREF */ | ||
| 1307 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); | ||
| 1308 | |||
| 1309 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
| 1310 | wm8990_write(codec, WM8990_ANTIPOP2, 0x0); | ||
| 1311 | break; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | codec->bias_level = level; | ||
| 1315 | return 0; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | #define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
| 1319 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
| 1320 | SNDRV_PCM_RATE_48000) | ||
| 1321 | |||
| 1322 | #define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
| 1323 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
| 1324 | |||
| 1325 | /* | ||
| 1326 | * The WM8990 supports 2 different and mutually exclusive DAI | ||
| 1327 | * configurations. | ||
| 1328 | * | ||
| 1329 | * 1. ADC/DAC on Primary Interface | ||
| 1330 | * 2. ADC on Primary Interface/DAC on secondary | ||
| 1331 | */ | ||
| 1332 | struct snd_soc_dai wm8990_dai = { | ||
| 1333 | /* ADC/DAC on primary */ | ||
| 1334 | .name = "WM8990 ADC/DAC Primary", | ||
| 1335 | .id = 1, | ||
| 1336 | .playback = { | ||
| 1337 | .stream_name = "Playback", | ||
| 1338 | .channels_min = 1, | ||
| 1339 | .channels_max = 2, | ||
| 1340 | .rates = WM8990_RATES, | ||
| 1341 | .formats = WM8990_FORMATS,}, | ||
| 1342 | .capture = { | ||
| 1343 | .stream_name = "Capture", | ||
| 1344 | .channels_min = 1, | ||
| 1345 | .channels_max = 2, | ||
| 1346 | .rates = WM8990_RATES, | ||
| 1347 | .formats = WM8990_FORMATS,}, | ||
| 1348 | .ops = { | ||
| 1349 | .hw_params = wm8990_hw_params,}, | ||
| 1350 | .dai_ops = { | ||
| 1351 | .digital_mute = wm8990_mute, | ||
| 1352 | .set_fmt = wm8990_set_dai_fmt, | ||
| 1353 | .set_clkdiv = wm8990_set_dai_clkdiv, | ||
| 1354 | .set_pll = wm8990_set_dai_pll, | ||
| 1355 | .set_sysclk = wm8990_set_dai_sysclk, | ||
| 1356 | }, | ||
| 1357 | }; | ||
| 1358 | EXPORT_SYMBOL_GPL(wm8990_dai); | ||
| 1359 | |||
| 1360 | static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 1361 | { | ||
| 1362 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 1363 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1364 | |||
| 1365 | /* we only need to suspend if we are a valid card */ | ||
| 1366 | if (!codec->card) | ||
| 1367 | return 0; | ||
| 1368 | |||
| 1369 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 1370 | return 0; | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | static int wm8990_resume(struct platform_device *pdev) | ||
| 1374 | { | ||
| 1375 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 1376 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1377 | int i; | ||
| 1378 | u8 data[2]; | ||
| 1379 | u16 *cache = codec->reg_cache; | ||
| 1380 | |||
| 1381 | /* we only need to resume if we are a valid card */ | ||
| 1382 | if (!codec->card) | ||
| 1383 | return 0; | ||
| 1384 | |||
| 1385 | /* Sync reg_cache with the hardware */ | ||
| 1386 | for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { | ||
| 1387 | if (i + 1 == WM8990_RESET) | ||
| 1388 | continue; | ||
| 1389 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); | ||
| 1390 | data[1] = cache[i] & 0x00ff; | ||
| 1391 | codec->hw_write(codec->control_data, data, 2); | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 1395 | return 0; | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | /* | ||
| 1399 | * initialise the WM8990 driver | ||
| 1400 | * register the mixer and dsp interfaces with the kernel | ||
| 1401 | */ | ||
| 1402 | static int wm8990_init(struct snd_soc_device *socdev) | ||
| 1403 | { | ||
| 1404 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1405 | u16 reg; | ||
| 1406 | int ret = 0; | ||
| 1407 | |||
| 1408 | codec->name = "WM8990"; | ||
| 1409 | codec->owner = THIS_MODULE; | ||
| 1410 | codec->read = wm8990_read_reg_cache; | ||
| 1411 | codec->write = wm8990_write; | ||
| 1412 | codec->set_bias_level = wm8990_set_bias_level; | ||
| 1413 | codec->dai = &wm8990_dai; | ||
| 1414 | codec->num_dai = 2; | ||
| 1415 | codec->reg_cache_size = ARRAY_SIZE(wm8990_reg); | ||
| 1416 | codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL); | ||
| 1417 | |||
| 1418 | if (codec->reg_cache == NULL) | ||
| 1419 | return -ENOMEM; | ||
| 1420 | |||
| 1421 | wm8990_reset(codec); | ||
| 1422 | |||
| 1423 | /* register pcms */ | ||
| 1424 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
| 1425 | if (ret < 0) { | ||
| 1426 | printk(KERN_ERR "wm8990: failed to create pcms\n"); | ||
| 1427 | goto pcm_err; | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | /* charge output caps */ | ||
| 1431 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
| 1432 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
| 1433 | |||
| 1434 | reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); | ||
| 1435 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); | ||
| 1436 | |||
| 1437 | reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & | ||
| 1438 | ~WM8990_GPIO1_SEL_MASK; | ||
| 1439 | wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); | ||
| 1440 | |||
| 1441 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
| 1442 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); | ||
| 1443 | |||
| 1444 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
| 1445 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
| 1446 | |||
| 1447 | wm8990_add_controls(codec); | ||
| 1448 | wm8990_add_widgets(codec); | ||
| 1449 | ret = snd_soc_register_card(socdev); | ||
| 1450 | if (ret < 0) { | ||
| 1451 | printk(KERN_ERR "wm8990: failed to register card\n"); | ||
| 1452 | goto card_err; | ||
| 1453 | } | ||
| 1454 | return ret; | ||
| 1455 | |||
| 1456 | card_err: | ||
| 1457 | snd_soc_free_pcms(socdev); | ||
| 1458 | snd_soc_dapm_free(socdev); | ||
| 1459 | pcm_err: | ||
| 1460 | kfree(codec->reg_cache); | ||
| 1461 | return ret; | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
| 1465 | around */ | ||
| 1466 | static struct snd_soc_device *wm8990_socdev; | ||
| 1467 | |||
| 1468 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 1469 | |||
| 1470 | /* | ||
| 1471 | * WM891 2 wire address is determined by GPIO5 | ||
| 1472 | * state during powerup. | ||
| 1473 | * low = 0x34 | ||
| 1474 | * high = 0x36 | ||
| 1475 | */ | ||
| 1476 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
| 1477 | |||
| 1478 | /* Magic definition of all other variables and things */ | ||
| 1479 | I2C_CLIENT_INSMOD; | ||
| 1480 | |||
| 1481 | static struct i2c_driver wm8990_i2c_driver; | ||
| 1482 | static struct i2c_client client_template; | ||
| 1483 | |||
| 1484 | static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
| 1485 | { | ||
| 1486 | struct snd_soc_device *socdev = wm8990_socdev; | ||
| 1487 | struct wm8990_setup_data *setup = socdev->codec_data; | ||
| 1488 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1489 | struct i2c_client *i2c; | ||
| 1490 | int ret; | ||
| 1491 | |||
| 1492 | if (addr != setup->i2c_address) | ||
| 1493 | return -ENODEV; | ||
| 1494 | |||
| 1495 | client_template.adapter = adap; | ||
| 1496 | client_template.addr = addr; | ||
| 1497 | |||
| 1498 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
| 1499 | if (i2c == NULL) { | ||
| 1500 | kfree(codec); | ||
| 1501 | return -ENOMEM; | ||
| 1502 | } | ||
| 1503 | i2c_set_clientdata(i2c, codec); | ||
| 1504 | codec->control_data = i2c; | ||
| 1505 | |||
| 1506 | ret = i2c_attach_client(i2c); | ||
| 1507 | if (ret < 0) { | ||
| 1508 | pr_err("failed to attach codec at addr %x\n", addr); | ||
| 1509 | goto err; | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | ret = wm8990_init(socdev); | ||
| 1513 | if (ret < 0) { | ||
| 1514 | pr_err("failed to initialise WM8990\n"); | ||
| 1515 | goto err; | ||
| 1516 | } | ||
| 1517 | return ret; | ||
| 1518 | |||
| 1519 | err: | ||
| 1520 | kfree(codec); | ||
| 1521 | kfree(i2c); | ||
| 1522 | return ret; | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | static int wm8990_i2c_detach(struct i2c_client *client) | ||
| 1526 | { | ||
| 1527 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
| 1528 | i2c_detach_client(client); | ||
| 1529 | kfree(codec->reg_cache); | ||
| 1530 | kfree(client); | ||
| 1531 | return 0; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | static int wm8990_i2c_attach(struct i2c_adapter *adap) | ||
| 1535 | { | ||
| 1536 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | static struct i2c_driver wm8990_i2c_driver = { | ||
| 1540 | .driver = { | ||
| 1541 | .name = "WM8990 I2C Codec", | ||
| 1542 | .owner = THIS_MODULE, | ||
| 1543 | }, | ||
| 1544 | .attach_adapter = wm8990_i2c_attach, | ||
| 1545 | .detach_client = wm8990_i2c_detach, | ||
| 1546 | .command = NULL, | ||
| 1547 | }; | ||
| 1548 | |||
| 1549 | static struct i2c_client client_template = { | ||
| 1550 | .name = "WM8990", | ||
| 1551 | .driver = &wm8990_i2c_driver, | ||
| 1552 | }; | ||
| 1553 | #endif | ||
| 1554 | |||
| 1555 | static int wm8990_probe(struct platform_device *pdev) | ||
| 1556 | { | ||
| 1557 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 1558 | struct wm8990_setup_data *setup; | ||
| 1559 | struct snd_soc_codec *codec; | ||
| 1560 | struct wm8990_priv *wm8990; | ||
| 1561 | int ret = 0; | ||
| 1562 | |||
| 1563 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | ||
| 1564 | |||
| 1565 | setup = socdev->codec_data; | ||
| 1566 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
| 1567 | if (codec == NULL) | ||
| 1568 | return -ENOMEM; | ||
| 1569 | |||
| 1570 | wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL); | ||
| 1571 | if (wm8990 == NULL) { | ||
| 1572 | kfree(codec); | ||
| 1573 | return -ENOMEM; | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | codec->private_data = wm8990; | ||
| 1577 | socdev->codec = codec; | ||
| 1578 | mutex_init(&codec->mutex); | ||
| 1579 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
| 1580 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
| 1581 | wm8990_socdev = socdev; | ||
| 1582 | |||
| 1583 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 1584 | if (setup->i2c_address) { | ||
| 1585 | normal_i2c[0] = setup->i2c_address; | ||
| 1586 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
| 1587 | ret = i2c_add_driver(&wm8990_i2c_driver); | ||
| 1588 | if (ret != 0) | ||
| 1589 | printk(KERN_ERR "can't add i2c driver"); | ||
| 1590 | } | ||
| 1591 | #else | ||
| 1592 | /* Add other interfaces here */ | ||
| 1593 | #endif | ||
| 1594 | return ret; | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | /* power down chip */ | ||
| 1598 | static int wm8990_remove(struct platform_device *pdev) | ||
| 1599 | { | ||
| 1600 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 1601 | struct snd_soc_codec *codec = socdev->codec; | ||
| 1602 | |||
| 1603 | if (codec->control_data) | ||
| 1604 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
| 1605 | snd_soc_free_pcms(socdev); | ||
| 1606 | snd_soc_dapm_free(socdev); | ||
| 1607 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 1608 | i2c_del_driver(&wm8990_i2c_driver); | ||
| 1609 | #endif | ||
| 1610 | kfree(codec->private_data); | ||
| 1611 | kfree(codec); | ||
| 1612 | |||
| 1613 | return 0; | ||
| 1614 | } | ||
| 1615 | |||
| 1616 | struct snd_soc_codec_device soc_codec_dev_wm8990 = { | ||
| 1617 | .probe = wm8990_probe, | ||
| 1618 | .remove = wm8990_remove, | ||
| 1619 | .suspend = wm8990_suspend, | ||
| 1620 | .resume = wm8990_resume, | ||
| 1621 | }; | ||
| 1622 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); | ||
| 1623 | |||
| 1624 | MODULE_DESCRIPTION("ASoC WM8990 driver"); | ||
| 1625 | MODULE_AUTHOR("Liam Girdwood"); | ||
| 1626 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h new file mode 100644 index 000000000000..6bea57485283 --- /dev/null +++ b/sound/soc/codecs/wm8990.h | |||
| @@ -0,0 +1,832 @@ | |||
| 1 | /* | ||
| 2 | * wm8990.h -- audio driver for WM8990 | ||
| 3 | * | ||
| 4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
| 5 | * Author: Graeme Gregory | ||
| 6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __WM8990REGISTERDEFS_H__ | ||
| 16 | #define __WM8990REGISTERDEFS_H__ | ||
| 17 | |||
| 18 | /* | ||
| 19 | * Register values. | ||
| 20 | */ | ||
| 21 | #define WM8990_RESET 0x00 | ||
| 22 | #define WM8990_POWER_MANAGEMENT_1 0x01 | ||
| 23 | #define WM8990_POWER_MANAGEMENT_2 0x02 | ||
| 24 | #define WM8990_POWER_MANAGEMENT_3 0x03 | ||
| 25 | #define WM8990_AUDIO_INTERFACE_1 0x04 | ||
| 26 | #define WM8990_AUDIO_INTERFACE_2 0x05 | ||
| 27 | #define WM8990_CLOCKING_1 0x06 | ||
| 28 | #define WM8990_CLOCKING_2 0x07 | ||
| 29 | #define WM8990_AUDIO_INTERFACE_3 0x08 | ||
| 30 | #define WM8990_AUDIO_INTERFACE_4 0x09 | ||
| 31 | #define WM8990_DAC_CTRL 0x0A | ||
| 32 | #define WM8990_LEFT_DAC_DIGITAL_VOLUME 0x0B | ||
| 33 | #define WM8990_RIGHT_DAC_DIGITAL_VOLUME 0x0C | ||
| 34 | #define WM8990_DIGITAL_SIDE_TONE 0x0D | ||
| 35 | #define WM8990_ADC_CTRL 0x0E | ||
| 36 | #define WM8990_LEFT_ADC_DIGITAL_VOLUME 0x0F | ||
| 37 | #define WM8990_RIGHT_ADC_DIGITAL_VOLUME 0x10 | ||
| 38 | #define WM8990_GPIO_CTRL_1 0x12 | ||
| 39 | #define WM8990_GPIO1_GPIO2 0x13 | ||
| 40 | #define WM8990_GPIO3_GPIO4 0x14 | ||
| 41 | #define WM8990_GPIO5_GPIO6 0x15 | ||
| 42 | #define WM8990_GPIOCTRL_2 0x16 | ||
| 43 | #define WM8990_GPIO_POL 0x17 | ||
| 44 | #define WM8990_LEFT_LINE_INPUT_1_2_VOLUME 0x18 | ||
| 45 | #define WM8990_LEFT_LINE_INPUT_3_4_VOLUME 0x19 | ||
| 46 | #define WM8990_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A | ||
| 47 | #define WM8990_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B | ||
| 48 | #define WM8990_LEFT_OUTPUT_VOLUME 0x1C | ||
| 49 | #define WM8990_RIGHT_OUTPUT_VOLUME 0x1D | ||
| 50 | #define WM8990_LINE_OUTPUTS_VOLUME 0x1E | ||
| 51 | #define WM8990_OUT3_4_VOLUME 0x1F | ||
| 52 | #define WM8990_LEFT_OPGA_VOLUME 0x20 | ||
| 53 | #define WM8990_RIGHT_OPGA_VOLUME 0x21 | ||
| 54 | #define WM8990_SPEAKER_VOLUME 0x22 | ||
| 55 | #define WM8990_CLASSD1 0x23 | ||
| 56 | #define WM8990_CLASSD3 0x25 | ||
| 57 | #define WM8990_INPUT_MIXER1 0x27 | ||
| 58 | #define WM8990_INPUT_MIXER2 0x28 | ||
| 59 | #define WM8990_INPUT_MIXER3 0x29 | ||
| 60 | #define WM8990_INPUT_MIXER4 0x2A | ||
| 61 | #define WM8990_INPUT_MIXER5 0x2B | ||
| 62 | #define WM8990_INPUT_MIXER6 0x2C | ||
| 63 | #define WM8990_OUTPUT_MIXER1 0x2D | ||
| 64 | #define WM8990_OUTPUT_MIXER2 0x2E | ||
| 65 | #define WM8990_OUTPUT_MIXER3 0x2F | ||
| 66 | #define WM8990_OUTPUT_MIXER4 0x30 | ||
| 67 | #define WM8990_OUTPUT_MIXER5 0x31 | ||
| 68 | #define WM8990_OUTPUT_MIXER6 0x32 | ||
| 69 | #define WM8990_OUT3_4_MIXER 0x33 | ||
| 70 | #define WM8990_LINE_MIXER1 0x34 | ||
| 71 | #define WM8990_LINE_MIXER2 0x35 | ||
| 72 | #define WM8990_SPEAKER_MIXER 0x36 | ||
| 73 | #define WM8990_ADDITIONAL_CONTROL 0x37 | ||
| 74 | #define WM8990_ANTIPOP1 0x38 | ||
| 75 | #define WM8990_ANTIPOP2 0x39 | ||
| 76 | #define WM8990_MICBIAS 0x3A | ||
| 77 | #define WM8990_PLL1 0x3C | ||
| 78 | #define WM8990_PLL2 0x3D | ||
| 79 | #define WM8990_PLL3 0x3E | ||
| 80 | #define WM8990_INTDRIVBITS 0x3F | ||
| 81 | |||
| 82 | #define WM8990_REGISTER_COUNT 60 | ||
| 83 | #define WM8990_MAX_REGISTER 0x3F | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Field Definitions. | ||
| 87 | */ | ||
| 88 | |||
| 89 | /* | ||
| 90 | * R0 (0x00) - Reset | ||
| 91 | */ | ||
| 92 | #define WM8990_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET_CHIP_ID */ | ||
| 93 | |||
| 94 | /* | ||
| 95 | * R1 (0x01) - Power Management (1) | ||
| 96 | */ | ||
| 97 | #define WM8990_SPK_ENA 0x1000 /* SPK_ENA */ | ||
| 98 | #define WM8990_SPK_ENA_BIT 12 | ||
| 99 | #define WM8990_OUT3_ENA 0x0800 /* OUT3_ENA */ | ||
| 100 | #define WM8990_OUT3_ENA_BIT 11 | ||
| 101 | #define WM8990_OUT4_ENA 0x0400 /* OUT4_ENA */ | ||
| 102 | #define WM8990_OUT4_ENA_BIT 10 | ||
| 103 | #define WM8990_LOUT_ENA 0x0200 /* LOUT_ENA */ | ||
| 104 | #define WM8990_LOUT_ENA_BIT 9 | ||
| 105 | #define WM8990_ROUT_ENA 0x0100 /* ROUT_ENA */ | ||
| 106 | #define WM8990_ROUT_ENA_BIT 8 | ||
| 107 | #define WM8990_MICBIAS_ENA 0x0010 /* MICBIAS_ENA */ | ||
| 108 | #define WM8990_MICBIAS_ENA_BIT 4 | ||
| 109 | #define WM8990_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */ | ||
| 110 | #define WM8990_VREF_ENA 0x0001 /* VREF_ENA */ | ||
| 111 | #define WM8990_VREF_ENA_BIT 0 | ||
| 112 | |||
| 113 | /* | ||
| 114 | * R2 (0x02) - Power Management (2) | ||
| 115 | */ | ||
| 116 | #define WM8990_PLL_ENA 0x8000 /* PLL_ENA */ | ||
| 117 | #define WM8990_PLL_ENA_BIT 15 | ||
| 118 | #define WM8990_TSHUT_ENA 0x4000 /* TSHUT_ENA */ | ||
| 119 | #define WM8990_TSHUT_ENA_BIT 14 | ||
| 120 | #define WM8990_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */ | ||
| 121 | #define WM8990_TSHUT_OPDIS_BIT 13 | ||
| 122 | #define WM8990_OPCLK_ENA 0x0800 /* OPCLK_ENA */ | ||
| 123 | #define WM8990_OPCLK_ENA_BIT 11 | ||
| 124 | #define WM8990_AINL_ENA 0x0200 /* AINL_ENA */ | ||
| 125 | #define WM8990_AINL_ENA_BIT 9 | ||
| 126 | #define WM8990_AINR_ENA 0x0100 /* AINR_ENA */ | ||
| 127 | #define WM8990_AINR_ENA_BIT 8 | ||
| 128 | #define WM8990_LIN34_ENA 0x0080 /* LIN34_ENA */ | ||
| 129 | #define WM8990_LIN34_ENA_BIT 7 | ||
| 130 | #define WM8990_LIN12_ENA 0x0040 /* LIN12_ENA */ | ||
| 131 | #define WM8990_LIN12_ENA_BIT 6 | ||
| 132 | #define WM8990_RIN34_ENA 0x0020 /* RIN34_ENA */ | ||
| 133 | #define WM8990_RIN34_ENA_BIT 5 | ||
| 134 | #define WM8990_RIN12_ENA 0x0010 /* RIN12_ENA */ | ||
| 135 | #define WM8990_RIN12_ENA_BIT 4 | ||
| 136 | #define WM8990_ADCL_ENA 0x0002 /* ADCL_ENA */ | ||
| 137 | #define WM8990_ADCL_ENA_BIT 1 | ||
| 138 | #define WM8990_ADCR_ENA 0x0001 /* ADCR_ENA */ | ||
| 139 | #define WM8990_ADCR_ENA_BIT 0 | ||
| 140 | |||
| 141 | /* | ||
| 142 | * R3 (0x03) - Power Management (3) | ||
| 143 | */ | ||
| 144 | #define WM8990_LON_ENA 0x2000 /* LON_ENA */ | ||
| 145 | #define WM8990_LON_ENA_BIT 13 | ||
| 146 | #define WM8990_LOP_ENA 0x1000 /* LOP_ENA */ | ||
| 147 | #define WM8990_LOP_ENA_BIT 12 | ||
| 148 | #define WM8990_RON_ENA 0x0800 /* RON_ENA */ | ||
| 149 | #define WM8990_RON_ENA_BIT 11 | ||
| 150 | #define WM8990_ROP_ENA 0x0400 /* ROP_ENA */ | ||
| 151 | #define WM8990_ROP_ENA_BIT 10 | ||
| 152 | #define WM8990_LOPGA_ENA 0x0080 /* LOPGA_ENA */ | ||
| 153 | #define WM8990_LOPGA_ENA_BIT 7 | ||
| 154 | #define WM8990_ROPGA_ENA 0x0040 /* ROPGA_ENA */ | ||
| 155 | #define WM8990_ROPGA_ENA_BIT 6 | ||
| 156 | #define WM8990_LOMIX_ENA 0x0020 /* LOMIX_ENA */ | ||
| 157 | #define WM8990_LOMIX_ENA_BIT 5 | ||
| 158 | #define WM8990_ROMIX_ENA 0x0010 /* ROMIX_ENA */ | ||
| 159 | #define WM8990_ROMIX_ENA_BIT 4 | ||
| 160 | #define WM8990_DACL_ENA 0x0002 /* DACL_ENA */ | ||
| 161 | #define WM8990_DACL_ENA_BIT 1 | ||
| 162 | #define WM8990_DACR_ENA 0x0001 /* DACR_ENA */ | ||
| 163 | #define WM8990_DACR_ENA_BIT 0 | ||
| 164 | |||
| 165 | /* | ||
| 166 | * R4 (0x04) - Audio Interface (1) | ||
| 167 | */ | ||
| 168 | #define WM8990_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */ | ||
| 169 | #define WM8990_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */ | ||
| 170 | #define WM8990_AIFADC_TDM 0x2000 /* AIFADC_TDM */ | ||
| 171 | #define WM8990_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */ | ||
| 172 | #define WM8990_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */ | ||
| 173 | #define WM8990_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */ | ||
| 174 | #define WM8990_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */ | ||
| 175 | #define WM8990_AIF_WL_16BITS (0 << 5) | ||
| 176 | #define WM8990_AIF_WL_20BITS (1 << 5) | ||
| 177 | #define WM8990_AIF_WL_24BITS (2 << 5) | ||
| 178 | #define WM8990_AIF_WL_32BITS (3 << 5) | ||
| 179 | #define WM8990_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */ | ||
| 180 | #define WM8990_AIF_TMF_RIGHTJ (0 << 3) | ||
| 181 | #define WM8990_AIF_TMF_LEFTJ (1 << 3) | ||
| 182 | #define WM8990_AIF_TMF_I2S (2 << 3) | ||
| 183 | #define WM8990_AIF_TMF_DSP (3 << 3) | ||
| 184 | |||
| 185 | /* | ||
| 186 | * R5 (0x05) - Audio Interface (2) | ||
| 187 | */ | ||
| 188 | #define WM8990_DACL_SRC 0x8000 /* DACL_SRC */ | ||
| 189 | #define WM8990_DACR_SRC 0x4000 /* DACR_SRC */ | ||
| 190 | #define WM8990_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ | ||
| 191 | #define WM8990_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ | ||
| 192 | #define WM8990_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST */ | ||
| 193 | #define WM8990_DAC_COMP 0x0010 /* DAC_COMP */ | ||
| 194 | #define WM8990_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */ | ||
| 195 | #define WM8990_ADC_COMP 0x0004 /* ADC_COMP */ | ||
| 196 | #define WM8990_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */ | ||
| 197 | #define WM8990_LOOPBACK 0x0001 /* LOOPBACK */ | ||
| 198 | |||
| 199 | /* | ||
| 200 | * R6 (0x06) - Clocking (1) | ||
| 201 | */ | ||
| 202 | #define WM8990_TOCLK_RATE 0x8000 /* TOCLK_RATE */ | ||
| 203 | #define WM8990_TOCLK_ENA 0x4000 /* TOCLK_ENA */ | ||
| 204 | #define WM8990_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */ | ||
| 205 | #define WM8990_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */ | ||
| 206 | #define WM8990_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */ | ||
| 207 | #define WM8990_BCLK_DIV_1 (0x0 << 1) | ||
| 208 | #define WM8990_BCLK_DIV_1_5 (0x1 << 1) | ||
| 209 | #define WM8990_BCLK_DIV_2 (0x2 << 1) | ||
| 210 | #define WM8990_BCLK_DIV_3 (0x3 << 1) | ||
| 211 | #define WM8990_BCLK_DIV_4 (0x4 << 1) | ||
| 212 | #define WM8990_BCLK_DIV_5_5 (0x5 << 1) | ||
| 213 | #define WM8990_BCLK_DIV_6 (0x6 << 1) | ||
| 214 | #define WM8990_BCLK_DIV_8 (0x7 << 1) | ||
| 215 | #define WM8990_BCLK_DIV_11 (0x8 << 1) | ||
| 216 | #define WM8990_BCLK_DIV_12 (0x9 << 1) | ||
| 217 | #define WM8990_BCLK_DIV_16 (0xA << 1) | ||
| 218 | #define WM8990_BCLK_DIV_22 (0xB << 1) | ||
| 219 | #define WM8990_BCLK_DIV_24 (0xC << 1) | ||
| 220 | #define WM8990_BCLK_DIV_32 (0xD << 1) | ||
| 221 | #define WM8990_BCLK_DIV_44 (0xE << 1) | ||
| 222 | #define WM8990_BCLK_DIV_48 (0xF << 1) | ||
| 223 | |||
| 224 | /* | ||
| 225 | * R7 (0x07) - Clocking (2) | ||
| 226 | */ | ||
| 227 | #define WM8990_MCLK_SRC 0x8000 /* MCLK_SRC */ | ||
| 228 | #define WM8990_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ | ||
| 229 | #define WM8990_CLK_FORCE 0x2000 /* CLK_FORCE */ | ||
| 230 | #define WM8990_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */ | ||
| 231 | #define WM8990_MCLK_DIV_1 (0 << 11) | ||
| 232 | #define WM8990_MCLK_DIV_2 (2 << 11) | ||
| 233 | #define WM8990_MCLK_INV 0x0400 /* MCLK_INV */ | ||
| 234 | #define WM8990_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV */ | ||
| 235 | #define WM8990_ADC_CLKDIV_1 (0 << 5) | ||
| 236 | #define WM8990_ADC_CLKDIV_1_5 (1 << 5) | ||
| 237 | #define WM8990_ADC_CLKDIV_2 (2 << 5) | ||
| 238 | #define WM8990_ADC_CLKDIV_3 (3 << 5) | ||
| 239 | #define WM8990_ADC_CLKDIV_4 (4 << 5) | ||
| 240 | #define WM8990_ADC_CLKDIV_5_5 (5 << 5) | ||
| 241 | #define WM8990_ADC_CLKDIV_6 (6 << 5) | ||
| 242 | #define WM8990_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */ | ||
| 243 | #define WM8990_DAC_CLKDIV_1 (0 << 2) | ||
| 244 | #define WM8990_DAC_CLKDIV_1_5 (1 << 2) | ||
| 245 | #define WM8990_DAC_CLKDIV_2 (2 << 2) | ||
| 246 | #define WM8990_DAC_CLKDIV_3 (3 << 2) | ||
| 247 | #define WM8990_DAC_CLKDIV_4 (4 << 2) | ||
| 248 | #define WM8990_DAC_CLKDIV_5_5 (5 << 2) | ||
| 249 | #define WM8990_DAC_CLKDIV_6 (6 << 2) | ||
| 250 | |||
| 251 | /* | ||
| 252 | * R8 (0x08) - Audio Interface (3) | ||
| 253 | */ | ||
| 254 | #define WM8990_AIF_MSTR1 0x8000 /* AIF_MSTR1 */ | ||
| 255 | #define WM8990_AIF_MSTR2 0x4000 /* AIF_MSTR2 */ | ||
| 256 | #define WM8990_AIF_SEL 0x2000 /* AIF_SEL */ | ||
| 257 | #define WM8990_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */ | ||
| 258 | #define WM8990_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE */ | ||
| 259 | |||
| 260 | /* | ||
| 261 | * R9 (0x09) - Audio Interface (4) | ||
| 262 | */ | ||
| 263 | #define WM8990_ALRCGPIO1 0x8000 /* ALRCGPIO1 */ | ||
| 264 | #define WM8990_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */ | ||
| 265 | #define WM8990_AIF_TRIS 0x2000 /* AIF_TRIS */ | ||
| 266 | #define WM8990_DACLRC_DIR 0x0800 /* DACLRC_DIR */ | ||
| 267 | #define WM8990_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE */ | ||
| 268 | |||
| 269 | /* | ||
| 270 | * R10 (0x0A) - DAC CTRL | ||
| 271 | */ | ||
| 272 | #define WM8990_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */ | ||
| 273 | #define WM8990_DAC_MONO 0x0200 /* DAC_MONO */ | ||
| 274 | #define WM8990_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */ | ||
| 275 | #define WM8990_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */ | ||
| 276 | #define WM8990_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */ | ||
| 277 | #define WM8990_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */ | ||
| 278 | #define WM8990_DAC_MUTE 0x0004 /* DAC_MUTE */ | ||
| 279 | #define WM8990_DACL_DATINV 0x0002 /* DACL_DATINV */ | ||
| 280 | #define WM8990_DACR_DATINV 0x0001 /* DACR_DATINV */ | ||
| 281 | |||
| 282 | /* | ||
| 283 | * R11 (0x0B) - Left DAC Digital Volume | ||
| 284 | */ | ||
| 285 | #define WM8990_DAC_VU 0x0100 /* DAC_VU */ | ||
| 286 | #define WM8990_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ | ||
| 287 | #define WM8990_DACL_VOL_SHIFT 0 | ||
| 288 | /* | ||
| 289 | * R12 (0x0C) - Right DAC Digital Volume | ||
| 290 | */ | ||
| 291 | #define WM8990_DAC_VU 0x0100 /* DAC_VU */ | ||
| 292 | #define WM8990_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ | ||
| 293 | #define WM8990_DACR_VOL_SHIFT 0 | ||
| 294 | /* | ||
| 295 | * R13 (0x0D) - Digital Side Tone | ||
| 296 | */ | ||
| 297 | #define WM8990_ADCL_DAC_SVOL_MASK 0x0F /* ADCL_DAC_SVOL */ | ||
| 298 | #define WM8990_ADCL_DAC_SVOL_SHIFT 9 | ||
| 299 | #define WM8990_ADCR_DAC_SVOL_MASK 0x0F /* ADCR_DAC_SVOL */ | ||
| 300 | #define WM8990_ADCR_DAC_SVOL_SHIFT 5 | ||
| 301 | #define WM8990_ADC_TO_DACL_MASK 0x03 /* ADC_TO_DACL - [3:2] */ | ||
| 302 | #define WM8990_ADC_TO_DACL_SHIFT 2 | ||
| 303 | #define WM8990_ADC_TO_DACR_MASK 0x03 /* ADC_TO_DACR - [1:0] */ | ||
| 304 | #define WM8990_ADC_TO_DACR_SHIFT 0 | ||
| 305 | |||
| 306 | /* | ||
| 307 | * R14 (0x0E) - ADC CTRL | ||
| 308 | */ | ||
| 309 | #define WM8990_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */ | ||
| 310 | #define WM8990_ADC_HPF_ENA_BIT 8 | ||
| 311 | #define WM8990_ADC_HPF_CUT_MASK 0x03 /* ADC_HPF_CUT - [6:5] */ | ||
| 312 | #define WM8990_ADC_HPF_CUT_SHIFT 5 | ||
| 313 | #define WM8990_ADCL_DATINV 0x0002 /* ADCL_DATINV */ | ||
| 314 | #define WM8990_ADCL_DATINV_BIT 1 | ||
| 315 | #define WM8990_ADCR_DATINV 0x0001 /* ADCR_DATINV */ | ||
| 316 | #define WM8990_ADCR_DATINV_BIT 0 | ||
| 317 | |||
| 318 | /* | ||
| 319 | * R15 (0x0F) - Left ADC Digital Volume | ||
| 320 | */ | ||
| 321 | #define WM8990_ADC_VU 0x0100 /* ADC_VU */ | ||
| 322 | #define WM8990_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ | ||
| 323 | #define WM8990_ADCL_VOL_SHIFT 0 | ||
| 324 | |||
| 325 | /* | ||
| 326 | * R16 (0x10) - Right ADC Digital Volume | ||
| 327 | */ | ||
| 328 | #define WM8990_ADC_VU 0x0100 /* ADC_VU */ | ||
| 329 | #define WM8990_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ | ||
| 330 | #define WM8990_ADCR_VOL_SHIFT 0 | ||
| 331 | |||
| 332 | /* | ||
| 333 | * R18 (0x12) - GPIO CTRL 1 | ||
| 334 | */ | ||
| 335 | #define WM8990_IRQ 0x1000 /* IRQ */ | ||
| 336 | #define WM8990_TEMPOK 0x0800 /* TEMPOK */ | ||
| 337 | #define WM8990_MICSHRT 0x0400 /* MICSHRT */ | ||
| 338 | #define WM8990_MICDET 0x0200 /* MICDET */ | ||
| 339 | #define WM8990_PLL_LCK 0x0100 /* PLL_LCK */ | ||
| 340 | #define WM8990_GPI8_STATUS 0x0080 /* GPI8_STATUS */ | ||
| 341 | #define WM8990_GPI7_STATUS 0x0040 /* GPI7_STATUS */ | ||
| 342 | #define WM8990_GPIO6_STATUS 0x0020 /* GPIO6_STATUS */ | ||
| 343 | #define WM8990_GPIO5_STATUS 0x0010 /* GPIO5_STATUS */ | ||
| 344 | #define WM8990_GPIO4_STATUS 0x0008 /* GPIO4_STATUS */ | ||
| 345 | #define WM8990_GPIO3_STATUS 0x0004 /* GPIO3_STATUS */ | ||
| 346 | #define WM8990_GPIO2_STATUS 0x0002 /* GPIO2_STATUS */ | ||
| 347 | #define WM8990_GPIO1_STATUS 0x0001 /* GPIO1_STATUS */ | ||
| 348 | |||
| 349 | /* | ||
| 350 | * R19 (0x13) - GPIO1 & GPIO2 | ||
| 351 | */ | ||
| 352 | #define WM8990_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */ | ||
| 353 | #define WM8990_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */ | ||
| 354 | #define WM8990_GPIO2_PU 0x2000 /* GPIO2_PU */ | ||
| 355 | #define WM8990_GPIO2_PD 0x1000 /* GPIO2_PD */ | ||
| 356 | #define WM8990_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */ | ||
| 357 | #define WM8990_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */ | ||
| 358 | #define WM8990_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */ | ||
| 359 | #define WM8990_GPIO1_PU 0x0020 /* GPIO1_PU */ | ||
| 360 | #define WM8990_GPIO1_PD 0x0010 /* GPIO1_PD */ | ||
| 361 | #define WM8990_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ | ||
| 362 | |||
| 363 | /* | ||
| 364 | * R20 (0x14) - GPIO3 & GPIO4 | ||
| 365 | */ | ||
| 366 | #define WM8990_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */ | ||
| 367 | #define WM8990_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */ | ||
| 368 | #define WM8990_GPIO4_PU 0x2000 /* GPIO4_PU */ | ||
| 369 | #define WM8990_GPIO4_PD 0x1000 /* GPIO4_PD */ | ||
| 370 | #define WM8990_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */ | ||
| 371 | #define WM8990_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */ | ||
| 372 | #define WM8990_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */ | ||
| 373 | #define WM8990_GPIO3_PU 0x0020 /* GPIO3_PU */ | ||
| 374 | #define WM8990_GPIO3_PD 0x0010 /* GPIO3_PD */ | ||
| 375 | #define WM8990_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */ | ||
| 376 | |||
| 377 | /* | ||
| 378 | * R21 (0x15) - GPIO5 & GPIO6 | ||
| 379 | */ | ||
| 380 | #define WM8990_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */ | ||
| 381 | #define WM8990_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */ | ||
| 382 | #define WM8990_GPIO6_PU 0x2000 /* GPIO6_PU */ | ||
| 383 | #define WM8990_GPIO6_PD 0x1000 /* GPIO6_PD */ | ||
| 384 | #define WM8990_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */ | ||
| 385 | #define WM8990_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */ | ||
| 386 | #define WM8990_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */ | ||
| 387 | #define WM8990_GPIO5_PU 0x0020 /* GPIO5_PU */ | ||
| 388 | #define WM8990_GPIO5_PD 0x0010 /* GPIO5_PD */ | ||
| 389 | #define WM8990_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */ | ||
| 390 | |||
| 391 | /* | ||
| 392 | * R22 (0x16) - GPIOCTRL 2 | ||
| 393 | */ | ||
| 394 | #define WM8990_RD_3W_ENA 0x8000 /* RD_3W_ENA */ | ||
| 395 | #define WM8990_MODE_3W4W 0x4000 /* MODE_3W4W */ | ||
| 396 | #define WM8990_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */ | ||
| 397 | #define WM8990_MICSHRT_IRQ_ENA 0x0400 /* MICSHRT_IRQ_ENA */ | ||
| 398 | #define WM8990_MICDET_IRQ_ENA 0x0200 /* MICDET_IRQ_ENA */ | ||
| 399 | #define WM8990_PLL_LCK_IRQ_ENA 0x0100 /* PLL_LCK_IRQ_ENA */ | ||
| 400 | #define WM8990_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */ | ||
| 401 | #define WM8990_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */ | ||
| 402 | #define WM8990_GPI8_ENA 0x0010 /* GPI8_ENA */ | ||
| 403 | #define WM8990_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */ | ||
| 404 | #define WM8990_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */ | ||
| 405 | #define WM8990_GPI7_ENA 0x0001 /* GPI7_ENA */ | ||
| 406 | |||
| 407 | /* | ||
| 408 | * R23 (0x17) - GPIO_POL | ||
| 409 | */ | ||
| 410 | #define WM8990_IRQ_INV 0x1000 /* IRQ_INV */ | ||
| 411 | #define WM8990_TEMPOK_POL 0x0800 /* TEMPOK_POL */ | ||
| 412 | #define WM8990_MICSHRT_POL 0x0400 /* MICSHRT_POL */ | ||
| 413 | #define WM8990_MICDET_POL 0x0200 /* MICDET_POL */ | ||
| 414 | #define WM8990_PLL_LCK_POL 0x0100 /* PLL_LCK_POL */ | ||
| 415 | #define WM8990_GPI8_POL 0x0080 /* GPI8_POL */ | ||
| 416 | #define WM8990_GPI7_POL 0x0040 /* GPI7_POL */ | ||
| 417 | #define WM8990_GPIO6_POL 0x0020 /* GPIO6_POL */ | ||
| 418 | #define WM8990_GPIO5_POL 0x0010 /* GPIO5_POL */ | ||
| 419 | #define WM8990_GPIO4_POL 0x0008 /* GPIO4_POL */ | ||
| 420 | #define WM8990_GPIO3_POL 0x0004 /* GPIO3_POL */ | ||
| 421 | #define WM8990_GPIO2_POL 0x0002 /* GPIO2_POL */ | ||
| 422 | #define WM8990_GPIO1_POL 0x0001 /* GPIO1_POL */ | ||
| 423 | |||
| 424 | /* | ||
| 425 | * R24 (0x18) - Left Line Input 1&2 Volume | ||
| 426 | */ | ||
| 427 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
| 428 | #define WM8990_LI12MUTE 0x0080 /* LI12MUTE */ | ||
| 429 | #define WM8990_LI12MUTE_BIT 7 | ||
| 430 | #define WM8990_LI12ZC 0x0040 /* LI12ZC */ | ||
| 431 | #define WM8990_LI12ZC_BIT 6 | ||
| 432 | #define WM8990_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */ | ||
| 433 | #define WM8990_LIN12VOL_SHIFT 0 | ||
| 434 | /* | ||
| 435 | * R25 (0x19) - Left Line Input 3&4 Volume | ||
| 436 | */ | ||
| 437 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
| 438 | #define WM8990_LI34MUTE 0x0080 /* LI34MUTE */ | ||
| 439 | #define WM8990_LI34MUTE_BIT 7 | ||
| 440 | #define WM8990_LI34ZC 0x0040 /* LI34ZC */ | ||
| 441 | #define WM8990_LI34ZC_BIT 6 | ||
| 442 | #define WM8990_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */ | ||
| 443 | #define WM8990_LIN34VOL_SHIFT 0 | ||
| 444 | |||
| 445 | /* | ||
| 446 | * R26 (0x1A) - Right Line Input 1&2 Volume | ||
| 447 | */ | ||
| 448 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
| 449 | #define WM8990_RI12MUTE 0x0080 /* RI12MUTE */ | ||
| 450 | #define WM8990_RI12MUTE_BIT 7 | ||
| 451 | #define WM8990_RI12ZC 0x0040 /* RI12ZC */ | ||
| 452 | #define WM8990_RI12ZC_BIT 6 | ||
| 453 | #define WM8990_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */ | ||
| 454 | #define WM8990_RIN12VOL_SHIFT 0 | ||
| 455 | |||
| 456 | /* | ||
| 457 | * R27 (0x1B) - Right Line Input 3&4 Volume | ||
| 458 | */ | ||
| 459 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
| 460 | #define WM8990_RI34MUTE 0x0080 /* RI34MUTE */ | ||
| 461 | #define WM8990_RI34MUTE_BIT 7 | ||
| 462 | #define WM8990_RI34ZC 0x0040 /* RI34ZC */ | ||
| 463 | #define WM8990_RI34ZC_BIT 6 | ||
| 464 | #define WM8990_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */ | ||
| 465 | #define WM8990_RIN34VOL_SHIFT 0 | ||
| 466 | |||
| 467 | /* | ||
| 468 | * R28 (0x1C) - Left Output Volume | ||
| 469 | */ | ||
| 470 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
| 471 | #define WM8990_LOZC 0x0080 /* LOZC */ | ||
| 472 | #define WM8990_LOZC_BIT 7 | ||
| 473 | #define WM8990_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */ | ||
| 474 | #define WM8990_LOUTVOL_SHIFT 0 | ||
| 475 | /* | ||
| 476 | * R29 (0x1D) - Right Output Volume | ||
| 477 | */ | ||
| 478 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
| 479 | #define WM8990_ROZC 0x0080 /* ROZC */ | ||
| 480 | #define WM8990_ROZC_BIT 7 | ||
| 481 | #define WM8990_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */ | ||
| 482 | #define WM8990_ROUTVOL_SHIFT 0 | ||
| 483 | /* | ||
| 484 | * R30 (0x1E) - Line Outputs Volume | ||
| 485 | */ | ||
| 486 | #define WM8990_LONMUTE 0x0040 /* LONMUTE */ | ||
| 487 | #define WM8990_LONMUTE_BIT 6 | ||
| 488 | #define WM8990_LOPMUTE 0x0020 /* LOPMUTE */ | ||
| 489 | #define WM8990_LOPMUTE_BIT 5 | ||
| 490 | #define WM8990_LOATTN 0x0010 /* LOATTN */ | ||
| 491 | #define WM8990_LOATTN_BIT 4 | ||
| 492 | #define WM8990_RONMUTE 0x0004 /* RONMUTE */ | ||
| 493 | #define WM8990_RONMUTE_BIT 2 | ||
| 494 | #define WM8990_ROPMUTE 0x0002 /* ROPMUTE */ | ||
| 495 | #define WM8990_ROPMUTE_BIT 1 | ||
| 496 | #define WM8990_ROATTN 0x0001 /* ROATTN */ | ||
| 497 | #define WM8990_ROATTN_BIT 0 | ||
| 498 | |||
| 499 | /* | ||
| 500 | * R31 (0x1F) - Out3/4 Volume | ||
| 501 | */ | ||
| 502 | #define WM8990_OUT3MUTE 0x0020 /* OUT3MUTE */ | ||
| 503 | #define WM8990_OUT3MUTE_BIT 5 | ||
| 504 | #define WM8990_OUT3ATTN 0x0010 /* OUT3ATTN */ | ||
| 505 | #define WM8990_OUT3ATTN_BIT 4 | ||
| 506 | #define WM8990_OUT4MUTE 0x0002 /* OUT4MUTE */ | ||
| 507 | #define WM8990_OUT4MUTE_BIT 1 | ||
| 508 | #define WM8990_OUT4ATTN 0x0001 /* OUT4ATTN */ | ||
| 509 | #define WM8990_OUT4ATTN_BIT 0 | ||
| 510 | |||
| 511 | /* | ||
| 512 | * R32 (0x20) - Left OPGA Volume | ||
| 513 | */ | ||
| 514 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
| 515 | #define WM8990_LOPGAZC 0x0080 /* LOPGAZC */ | ||
| 516 | #define WM8990_LOPGAZC_BIT 7 | ||
| 517 | #define WM8990_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */ | ||
| 518 | #define WM8990_LOPGAVOL_SHIFT 0 | ||
| 519 | |||
| 520 | /* | ||
| 521 | * R33 (0x21) - Right OPGA Volume | ||
| 522 | */ | ||
| 523 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
| 524 | #define WM8990_ROPGAZC 0x0080 /* ROPGAZC */ | ||
| 525 | #define WM8990_ROPGAZC_BIT 7 | ||
| 526 | #define WM8990_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */ | ||
| 527 | #define WM8990_ROPGAVOL_SHIFT 0 | ||
| 528 | /* | ||
| 529 | * R34 (0x22) - Speaker Volume | ||
| 530 | */ | ||
| 531 | #define WM8990_SPKVOL_MASK 0x0003 /* SPKVOL - [1:0] */ | ||
| 532 | #define WM8990_SPKVOL_SHIFT 0 | ||
| 533 | |||
| 534 | /* | ||
| 535 | * R35 (0x23) - ClassD1 | ||
| 536 | */ | ||
| 537 | #define WM8990_CDMODE 0x0100 /* CDMODE */ | ||
| 538 | #define WM8990_CDMODE_BIT 8 | ||
| 539 | |||
| 540 | /* | ||
| 541 | * R37 (0x25) - ClassD3 | ||
| 542 | */ | ||
| 543 | #define WM8990_DCGAIN_MASK 0x0007 /* DCGAIN - [5:3] */ | ||
| 544 | #define WM8990_DCGAIN_SHIFT 3 | ||
| 545 | #define WM8990_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */ | ||
| 546 | #define WM8990_ACGAIN_SHIFT 0 | ||
| 547 | /* | ||
| 548 | * R39 (0x27) - Input Mixer1 | ||
| 549 | */ | ||
| 550 | #define WM8990_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */ | ||
| 551 | #define WM8990_AINLMODE_SHIFT 2 | ||
| 552 | #define WM8990_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */ | ||
| 553 | #define WM8990_AINRMODE_SHIFT 0 | ||
| 554 | |||
| 555 | /* | ||
| 556 | * R40 (0x28) - Input Mixer2 | ||
| 557 | */ | ||
| 558 | #define WM8990_LMP4 0x0080 /* LMP4 */ | ||
| 559 | #define WM8990_LMP4_BIT 7 /* LMP4 */ | ||
| 560 | #define WM8990_LMN3 0x0040 /* LMN3 */ | ||
| 561 | #define WM8990_LMN3_BIT 6 /* LMN3 */ | ||
| 562 | #define WM8990_LMP2 0x0020 /* LMP2 */ | ||
| 563 | #define WM8990_LMP2_BIT 5 /* LMP2 */ | ||
| 564 | #define WM8990_LMN1 0x0010 /* LMN1 */ | ||
| 565 | #define WM8990_LMN1_BIT 4 /* LMN1 */ | ||
| 566 | #define WM8990_RMP4 0x0008 /* RMP4 */ | ||
| 567 | #define WM8990_RMP4_BIT 3 /* RMP4 */ | ||
| 568 | #define WM8990_RMN3 0x0004 /* RMN3 */ | ||
| 569 | #define WM8990_RMN3_BIT 2 /* RMN3 */ | ||
| 570 | #define WM8990_RMP2 0x0002 /* RMP2 */ | ||
| 571 | #define WM8990_RMP2_BIT 1 /* RMP2 */ | ||
| 572 | #define WM8990_RMN1 0x0001 /* RMN1 */ | ||
| 573 | #define WM8990_RMN1_BIT 0 /* RMN1 */ | ||
| 574 | |||
| 575 | /* | ||
| 576 | * R41 (0x29) - Input Mixer3 | ||
| 577 | */ | ||
| 578 | #define WM8990_L34MNB 0x0100 /* L34MNB */ | ||
| 579 | #define WM8990_L34MNB_BIT 8 | ||
| 580 | #define WM8990_L34MNBST 0x0080 /* L34MNBST */ | ||
| 581 | #define WM8990_L34MNBST_BIT 7 | ||
| 582 | #define WM8990_L12MNB 0x0020 /* L12MNB */ | ||
| 583 | #define WM8990_L12MNB_BIT 5 | ||
| 584 | #define WM8990_L12MNBST 0x0010 /* L12MNBST */ | ||
| 585 | #define WM8990_L12MNBST_BIT 4 | ||
| 586 | #define WM8990_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */ | ||
| 587 | #define WM8990_LDBVOL_SHIFT 0 | ||
| 588 | |||
| 589 | /* | ||
| 590 | * R42 (0x2A) - Input Mixer4 | ||
| 591 | */ | ||
| 592 | #define WM8990_R34MNB 0x0100 /* R34MNB */ | ||
| 593 | #define WM8990_R34MNB_BIT 8 | ||
| 594 | #define WM8990_R34MNBST 0x0080 /* R34MNBST */ | ||
| 595 | #define WM8990_R34MNBST_BIT 7 | ||
| 596 | #define WM8990_R12MNB 0x0020 /* R12MNB */ | ||
| 597 | #define WM8990_R12MNB_BIT 5 | ||
| 598 | #define WM8990_R12MNBST 0x0010 /* R12MNBST */ | ||
| 599 | #define WM8990_R12MNBST_BIT 4 | ||
| 600 | #define WM8990_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */ | ||
| 601 | #define WM8990_RDBVOL_SHIFT 0 | ||
| 602 | |||
| 603 | /* | ||
| 604 | * R43 (0x2B) - Input Mixer5 | ||
| 605 | */ | ||
| 606 | #define WM8990_LI2BVOL_MASK 0x07 /* LI2BVOL - [8:6] */ | ||
| 607 | #define WM8990_LI2BVOL_SHIFT 6 | ||
| 608 | #define WM8990_LR4BVOL_MASK 0x07 /* LR4BVOL - [5:3] */ | ||
| 609 | #define WM8990_LR4BVOL_SHIFT 3 | ||
| 610 | #define WM8990_LL4BVOL_MASK 0x07 /* LL4BVOL - [2:0] */ | ||
| 611 | #define WM8990_LL4BVOL_SHIFT 0 | ||
| 612 | |||
| 613 | /* | ||
| 614 | * R44 (0x2C) - Input Mixer6 | ||
| 615 | */ | ||
| 616 | #define WM8990_RI2BVOL_MASK 0x07 /* RI2BVOL - [8:6] */ | ||
| 617 | #define WM8990_RI2BVOL_SHIFT 6 | ||
| 618 | #define WM8990_RL4BVOL_MASK 0x07 /* RL4BVOL - [5:3] */ | ||
| 619 | #define WM8990_RL4BVOL_SHIFT 3 | ||
| 620 | #define WM8990_RR4BVOL_MASK 0x07 /* RR4BVOL - [2:0] */ | ||
| 621 | #define WM8990_RR4BVOL_SHIFT 0 | ||
| 622 | |||
| 623 | /* | ||
| 624 | * R45 (0x2D) - Output Mixer1 | ||
| 625 | */ | ||
| 626 | #define WM8990_LRBLO 0x0080 /* LRBLO */ | ||
| 627 | #define WM8990_LRBLO_BIT 7 | ||
| 628 | #define WM8990_LLBLO 0x0040 /* LLBLO */ | ||
| 629 | #define WM8990_LLBLO_BIT 6 | ||
| 630 | #define WM8990_LRI3LO 0x0020 /* LRI3LO */ | ||
| 631 | #define WM8990_LRI3LO_BIT 5 | ||
| 632 | #define WM8990_LLI3LO 0x0010 /* LLI3LO */ | ||
| 633 | #define WM8990_LLI3LO_BIT 4 | ||
| 634 | #define WM8990_LR12LO 0x0008 /* LR12LO */ | ||
| 635 | #define WM8990_LR12LO_BIT 3 | ||
| 636 | #define WM8990_LL12LO 0x0004 /* LL12LO */ | ||
| 637 | #define WM8990_LL12LO_BIT 2 | ||
| 638 | #define WM8990_LDLO 0x0001 /* LDLO */ | ||
| 639 | #define WM8990_LDLO_BIT 0 | ||
| 640 | |||
| 641 | /* | ||
| 642 | * R46 (0x2E) - Output Mixer2 | ||
| 643 | */ | ||
| 644 | #define WM8990_RLBRO 0x0080 /* RLBRO */ | ||
| 645 | #define WM8990_RLBRO_BIT 7 | ||
| 646 | #define WM8990_RRBRO 0x0040 /* RRBRO */ | ||
| 647 | #define WM8990_RRBRO_BIT 6 | ||
| 648 | #define WM8990_RLI3RO 0x0020 /* RLI3RO */ | ||
| 649 | #define WM8990_RLI3RO_BIT 5 | ||
| 650 | #define WM8990_RRI3RO 0x0010 /* RRI3RO */ | ||
| 651 | #define WM8990_RRI3RO_BIT 4 | ||
| 652 | #define WM8990_RL12RO 0x0008 /* RL12RO */ | ||
| 653 | #define WM8990_RL12RO_BIT 3 | ||
| 654 | #define WM8990_RR12RO 0x0004 /* RR12RO */ | ||
| 655 | #define WM8990_RR12RO_BIT 2 | ||
| 656 | #define WM8990_RDRO 0x0001 /* RDRO */ | ||
| 657 | #define WM8990_RDRO_BIT 0 | ||
| 658 | |||
| 659 | /* | ||
| 660 | * R47 (0x2F) - Output Mixer3 | ||
| 661 | */ | ||
| 662 | #define WM8990_LLI3LOVOL_MASK 0x07 /* LLI3LOVOL - [8:6] */ | ||
| 663 | #define WM8990_LLI3LOVOL_SHIFT 6 | ||
| 664 | #define WM8990_LR12LOVOL_MASK 0x07 /* LR12LOVOL - [5:3] */ | ||
| 665 | #define WM8990_LR12LOVOL_SHIFT 3 | ||
| 666 | #define WM8990_LL12LOVOL_MASK 0x07 /* LL12LOVOL - [2:0] */ | ||
| 667 | #define WM8990_LL12LOVOL_SHIFT 0 | ||
| 668 | |||
| 669 | /* | ||
| 670 | * R48 (0x30) - Output Mixer4 | ||
| 671 | */ | ||
| 672 | #define WM8990_RRI3ROVOL_MASK 0x07 /* RRI3ROVOL - [8:6] */ | ||
| 673 | #define WM8990_RRI3ROVOL_SHIFT 6 | ||
| 674 | #define WM8990_RL12ROVOL_MASK 0x07 /* RL12ROVOL - [5:3] */ | ||
| 675 | #define WM8990_RL12ROVOL_SHIFT 3 | ||
| 676 | #define WM8990_RR12ROVOL_MASK 0x07 /* RR12ROVOL - [2:0] */ | ||
| 677 | #define WM8990_RR12ROVOL_SHIFT 0 | ||
| 678 | |||
| 679 | /* | ||
| 680 | * R49 (0x31) - Output Mixer5 | ||
| 681 | */ | ||
| 682 | #define WM8990_LRI3LOVOL_MASK 0x07 /* LRI3LOVOL - [8:6] */ | ||
| 683 | #define WM8990_LRI3LOVOL_SHIFT 6 | ||
| 684 | #define WM8990_LRBLOVOL_MASK 0x07 /* LRBLOVOL - [5:3] */ | ||
| 685 | #define WM8990_LRBLOVOL_SHIFT 3 | ||
| 686 | #define WM8990_LLBLOVOL_MASK 0x07 /* LLBLOVOL - [2:0] */ | ||
| 687 | #define WM8990_LLBLOVOL_SHIFT 0 | ||
| 688 | |||
| 689 | /* | ||
| 690 | * R50 (0x32) - Output Mixer6 | ||
| 691 | */ | ||
| 692 | #define WM8990_RLI3ROVOL_MASK 0x07 /* RLI3ROVOL - [8:6] */ | ||
| 693 | #define WM8990_RLI3ROVOL_SHIFT 6 | ||
| 694 | #define WM8990_RLBROVOL_MASK 0x07 /* RLBROVOL - [5:3] */ | ||
| 695 | #define WM8990_RLBROVOL_SHIFT 3 | ||
| 696 | #define WM8990_RRBROVOL_MASK 0x07 /* RRBROVOL - [2:0] */ | ||
| 697 | #define WM8990_RRBROVOL_SHIFT 0 | ||
| 698 | |||
| 699 | /* | ||
| 700 | * R51 (0x33) - Out3/4 Mixer | ||
| 701 | */ | ||
| 702 | #define WM8990_VSEL_MASK 0x0180 /* VSEL - [8:7] */ | ||
| 703 | #define WM8990_LI4O3 0x0020 /* LI4O3 */ | ||
| 704 | #define WM8990_LI4O3_BIT 5 | ||
| 705 | #define WM8990_LPGAO3 0x0010 /* LPGAO3 */ | ||
| 706 | #define WM8990_LPGAO3_BIT 4 | ||
| 707 | #define WM8990_RI4O4 0x0002 /* RI4O4 */ | ||
| 708 | #define WM8990_RI4O4_BIT 1 | ||
| 709 | #define WM8990_RPGAO4 0x0001 /* RPGAO4 */ | ||
| 710 | #define WM8990_RPGAO4_BIT 0 | ||
| 711 | /* | ||
| 712 | * R52 (0x34) - Line Mixer1 | ||
| 713 | */ | ||
| 714 | #define WM8990_LLOPGALON 0x0040 /* LLOPGALON */ | ||
| 715 | #define WM8990_LLOPGALON_BIT 6 | ||
| 716 | #define WM8990_LROPGALON 0x0020 /* LROPGALON */ | ||
| 717 | #define WM8990_LROPGALON_BIT 5 | ||
| 718 | #define WM8990_LOPLON 0x0010 /* LOPLON */ | ||
| 719 | #define WM8990_LOPLON_BIT 4 | ||
| 720 | #define WM8990_LR12LOP 0x0004 /* LR12LOP */ | ||
| 721 | #define WM8990_LR12LOP_BIT 2 | ||
| 722 | #define WM8990_LL12LOP 0x0002 /* LL12LOP */ | ||
| 723 | #define WM8990_LL12LOP_BIT 1 | ||
| 724 | #define WM8990_LLOPGALOP 0x0001 /* LLOPGALOP */ | ||
| 725 | #define WM8990_LLOPGALOP_BIT 0 | ||
| 726 | /* | ||
| 727 | * R53 (0x35) - Line Mixer2 | ||
| 728 | */ | ||
| 729 | #define WM8990_RROPGARON 0x0040 /* RROPGARON */ | ||
| 730 | #define WM8990_RROPGARON_BIT 6 | ||
| 731 | #define WM8990_RLOPGARON 0x0020 /* RLOPGARON */ | ||
| 732 | #define WM8990_RLOPGARON_BIT 5 | ||
| 733 | #define WM8990_ROPRON 0x0010 /* ROPRON */ | ||
| 734 | #define WM8990_ROPRON_BIT 4 | ||
| 735 | #define WM8990_RL12ROP 0x0004 /* RL12ROP */ | ||
| 736 | #define WM8990_RL12ROP_BIT 2 | ||
| 737 | #define WM8990_RR12ROP 0x0002 /* RR12ROP */ | ||
| 738 | #define WM8990_RR12ROP_BIT 1 | ||
| 739 | #define WM8990_RROPGAROP 0x0001 /* RROPGAROP */ | ||
| 740 | #define WM8990_RROPGAROP_BIT 0 | ||
| 741 | |||
| 742 | /* | ||
| 743 | * R54 (0x36) - Speaker Mixer | ||
| 744 | */ | ||
| 745 | #define WM8990_LB2SPK 0x0080 /* LB2SPK */ | ||
| 746 | #define WM8990_LB2SPK_BIT 7 | ||
| 747 | #define WM8990_RB2SPK 0x0040 /* RB2SPK */ | ||
| 748 | #define WM8990_RB2SPK_BIT 6 | ||
| 749 | #define WM8990_LI2SPK 0x0020 /* LI2SPK */ | ||
| 750 | #define WM8990_LI2SPK_BIT 5 | ||
| 751 | #define WM8990_RI2SPK 0x0010 /* RI2SPK */ | ||
| 752 | #define WM8990_RI2SPK_BIT 4 | ||
| 753 | #define WM8990_LOPGASPK 0x0008 /* LOPGASPK */ | ||
| 754 | #define WM8990_LOPGASPK_BIT 3 | ||
| 755 | #define WM8990_ROPGASPK 0x0004 /* ROPGASPK */ | ||
| 756 | #define WM8990_ROPGASPK_BIT 2 | ||
| 757 | #define WM8990_LDSPK 0x0002 /* LDSPK */ | ||
| 758 | #define WM8990_LDSPK_BIT 1 | ||
| 759 | #define WM8990_RDSPK 0x0001 /* RDSPK */ | ||
| 760 | #define WM8990_RDSPK_BIT 0 | ||
| 761 | |||
| 762 | /* | ||
| 763 | * R55 (0x37) - Additional Control | ||
| 764 | */ | ||
| 765 | #define WM8990_VROI 0x0001 /* VROI */ | ||
| 766 | |||
| 767 | /* | ||
| 768 | * R56 (0x38) - AntiPOP1 | ||
| 769 | */ | ||
| 770 | #define WM8990_DIS_LLINE 0x0020 /* DIS_LLINE */ | ||
| 771 | #define WM8990_DIS_RLINE 0x0010 /* DIS_RLINE */ | ||
| 772 | #define WM8990_DIS_OUT3 0x0008 /* DIS_OUT3 */ | ||
| 773 | #define WM8990_DIS_OUT4 0x0004 /* DIS_OUT4 */ | ||
| 774 | #define WM8990_DIS_LOUT 0x0002 /* DIS_LOUT */ | ||
| 775 | #define WM8990_DIS_ROUT 0x0001 /* DIS_ROUT */ | ||
| 776 | |||
| 777 | /* | ||
| 778 | * R57 (0x39) - AntiPOP2 | ||
| 779 | */ | ||
| 780 | #define WM8990_SOFTST 0x0040 /* SOFTST */ | ||
| 781 | #define WM8990_BUFIOEN 0x0008 /* BUFIOEN */ | ||
| 782 | #define WM8990_BUFDCOPEN 0x0004 /* BUFDCOPEN */ | ||
| 783 | #define WM8990_POBCTRL 0x0002 /* POBCTRL */ | ||
| 784 | #define WM8990_VMIDTOG 0x0001 /* VMIDTOG */ | ||
| 785 | |||
| 786 | /* | ||
| 787 | * R58 (0x3A) - MICBIAS | ||
| 788 | */ | ||
| 789 | #define WM8990_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */ | ||
| 790 | #define WM8990_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */ | ||
| 791 | #define WM8990_MCD 0x0004 /* MCD */ | ||
| 792 | #define WM8990_MBSEL 0x0001 /* MBSEL */ | ||
| 793 | |||
| 794 | /* | ||
| 795 | * R60 (0x3C) - PLL1 | ||
| 796 | */ | ||
| 797 | #define WM8990_SDM 0x0080 /* SDM */ | ||
| 798 | #define WM8990_PRESCALE 0x0040 /* PRESCALE */ | ||
| 799 | #define WM8990_PLLN_MASK 0x000F /* PLLN - [3:0] */ | ||
| 800 | |||
| 801 | /* | ||
| 802 | * R61 (0x3D) - PLL2 | ||
| 803 | */ | ||
| 804 | #define WM8990_PLLK1_MASK 0x00FF /* PLLK1 - [7:0] */ | ||
| 805 | |||
| 806 | /* | ||
| 807 | * R62 (0x3E) - PLL3 | ||
| 808 | */ | ||
| 809 | #define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */ | ||
| 810 | |||
| 811 | /* | ||
| 812 | * R63 (0x3F) - Internal Driver Bits | ||
| 813 | */ | ||
| 814 | #define WM8990_INMIXL_PWR_BIT 0 | ||
| 815 | #define WM8990_AINLMUX_PWR_BIT 1 | ||
| 816 | #define WM8990_INMIXR_PWR_BIT 2 | ||
| 817 | #define WM8990_AINRMUX_PWR_BIT 3 | ||
| 818 | |||
| 819 | struct wm8990_setup_data { | ||
| 820 | unsigned short i2c_address; | ||
| 821 | }; | ||
| 822 | |||
| 823 | #define WM8990_MCLK_DIV 0 | ||
| 824 | #define WM8990_DACCLK_DIV 1 | ||
| 825 | #define WM8990_ADCCLK_DIV 2 | ||
| 826 | #define WM8990_BCLK_DIV 3 | ||
| 827 | |||
| 828 | extern struct snd_soc_dai wm8990_dai; | ||
| 829 | extern struct snd_soc_codec_device soc_codec_dev_wm8990; | ||
| 830 | |||
| 831 | #endif /* __WM8990REGISTERDEFS_H__ */ | ||
| 832 | /*------------------------------ END OF FILE ---------------------------------*/ | ||
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 76c1e2d33e7d..9fc8edd82225 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
| @@ -9,9 +9,6 @@ | |||
| 9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. | 11 | * option) any later version. |
| 12 | * | ||
| 13 | * Revision history | ||
| 14 | * 4th Feb 2006 Initial version. | ||
| 15 | */ | 12 | */ |
| 16 | 13 | ||
| 17 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| @@ -25,6 +22,7 @@ | |||
| 25 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
| 26 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
| 27 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
| 25 | #include "wm9712.h" | ||
| 28 | 26 | ||
| 29 | #define WM9712_VERSION "0.4" | 27 | #define WM9712_VERSION "0.4" |
| 30 | 28 | ||
| @@ -351,7 +349,7 @@ SND_SOC_DAPM_INPUT("MIC1"), | |||
| 351 | SND_SOC_DAPM_INPUT("MIC2"), | 349 | SND_SOC_DAPM_INPUT("MIC2"), |
| 352 | }; | 350 | }; |
| 353 | 351 | ||
| 354 | static const char *audio_map[][3] = { | 352 | static const struct snd_soc_dapm_route audio_map[] = { |
| 355 | /* virtual mixer - mixes left & right channels for spk and mono */ | 353 | /* virtual mixer - mixes left & right channels for spk and mono */ |
| 356 | {"AC97 Mixer", NULL, "Left DAC"}, | 354 | {"AC97 Mixer", NULL, "Left DAC"}, |
| 357 | {"AC97 Mixer", NULL, "Right DAC"}, | 355 | {"AC97 Mixer", NULL, "Right DAC"}, |
| @@ -446,21 +444,14 @@ static const char *audio_map[][3] = { | |||
| 446 | {"Speaker PGA", NULL, "Speaker Mux"}, | 444 | {"Speaker PGA", NULL, "Speaker Mux"}, |
| 447 | {"LOUT2", NULL, "Speaker PGA"}, | 445 | {"LOUT2", NULL, "Speaker PGA"}, |
| 448 | {"ROUT2", NULL, "Speaker PGA"}, | 446 | {"ROUT2", NULL, "Speaker PGA"}, |
| 449 | |||
| 450 | {NULL, NULL, NULL}, | ||
| 451 | }; | 447 | }; |
| 452 | 448 | ||
| 453 | static int wm9712_add_widgets(struct snd_soc_codec *codec) | 449 | static int wm9712_add_widgets(struct snd_soc_codec *codec) |
| 454 | { | 450 | { |
| 455 | int i; | 451 | snd_soc_dapm_new_controls(codec, wm9712_dapm_widgets, |
| 456 | 452 | ARRAY_SIZE(wm9712_dapm_widgets)); | |
| 457 | for (i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) | ||
| 458 | snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]); | ||
| 459 | 453 | ||
| 460 | /* set up audio path connects */ | 454 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 461 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
| 462 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 463 | audio_map[i][1], audio_map[i][2]); | ||
| 464 | 455 | ||
| 465 | snd_soc_dapm_new_widgets(codec); | 456 | snd_soc_dapm_new_widgets(codec); |
| 466 | return 0; | 457 | return 0; |
| @@ -541,7 +532,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) | |||
| 541 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 532 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
| 542 | SNDRV_PCM_RATE_48000) | 533 | SNDRV_PCM_RATE_48000) |
| 543 | 534 | ||
| 544 | struct snd_soc_codec_dai wm9712_dai[] = { | 535 | struct snd_soc_dai wm9712_dai[] = { |
| 545 | { | 536 | { |
| 546 | .name = "AC97 HiFi", | 537 | .name = "AC97 HiFi", |
| 547 | .type = SND_SOC_DAI_AC97_BUS, | 538 | .type = SND_SOC_DAI_AC97_BUS, |
| @@ -574,23 +565,23 @@ struct snd_soc_codec_dai wm9712_dai[] = { | |||
| 574 | }; | 565 | }; |
| 575 | EXPORT_SYMBOL_GPL(wm9712_dai); | 566 | EXPORT_SYMBOL_GPL(wm9712_dai); |
| 576 | 567 | ||
| 577 | static int wm9712_dapm_event(struct snd_soc_codec *codec, int event) | 568 | static int wm9712_set_bias_level(struct snd_soc_codec *codec, |
| 569 | enum snd_soc_bias_level level) | ||
| 578 | { | 570 | { |
| 579 | switch (event) { | 571 | switch (level) { |
| 580 | case SNDRV_CTL_POWER_D0: /* full On */ | 572 | case SND_SOC_BIAS_ON: |
| 581 | case SNDRV_CTL_POWER_D1: /* partial On */ | 573 | case SND_SOC_BIAS_PREPARE: |
| 582 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
| 583 | break; | 574 | break; |
| 584 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 575 | case SND_SOC_BIAS_STANDBY: |
| 585 | ac97_write(codec, AC97_POWERDOWN, 0x0000); | 576 | ac97_write(codec, AC97_POWERDOWN, 0x0000); |
| 586 | break; | 577 | break; |
| 587 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 578 | case SND_SOC_BIAS_OFF: |
| 588 | /* disable everything including AC link */ | 579 | /* disable everything including AC link */ |
| 589 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); | 580 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); |
| 590 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 581 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
| 591 | break; | 582 | break; |
| 592 | } | 583 | } |
| 593 | codec->dapm_state = event; | 584 | codec->bias_level = level; |
| 594 | return 0; | 585 | return 0; |
| 595 | } | 586 | } |
| 596 | 587 | ||
| @@ -598,12 +589,12 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) | |||
| 598 | { | 589 | { |
| 599 | if (try_warm && soc_ac97_ops.warm_reset) { | 590 | if (try_warm && soc_ac97_ops.warm_reset) { |
| 600 | soc_ac97_ops.warm_reset(codec->ac97); | 591 | soc_ac97_ops.warm_reset(codec->ac97); |
| 601 | if (!(ac97_read(codec, 0) & 0x8000)) | 592 | if (ac97_read(codec, 0) == wm9712_reg[0]) |
| 602 | return 1; | 593 | return 1; |
| 603 | } | 594 | } |
| 604 | 595 | ||
| 605 | soc_ac97_ops.reset(codec->ac97); | 596 | soc_ac97_ops.reset(codec->ac97); |
| 606 | if (ac97_read(codec, 0) & 0x8000) | 597 | if (ac97_read(codec, 0) != wm9712_reg[0]) |
| 607 | goto err; | 598 | goto err; |
| 608 | return 0; | 599 | return 0; |
| 609 | 600 | ||
| @@ -618,7 +609,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev, | |||
| 618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 609 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 619 | struct snd_soc_codec *codec = socdev->codec; | 610 | struct snd_soc_codec *codec = socdev->codec; |
| 620 | 611 | ||
| 621 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 612 | wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 622 | return 0; | 613 | return 0; |
| 623 | } | 614 | } |
| 624 | 615 | ||
| @@ -635,7 +626,7 @@ static int wm9712_soc_resume(struct platform_device *pdev) | |||
| 635 | return ret; | 626 | return ret; |
| 636 | } | 627 | } |
| 637 | 628 | ||
| 638 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 629 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 639 | 630 | ||
| 640 | if (ret == 0) { | 631 | if (ret == 0) { |
| 641 | /* Sync reg_cache with the hardware after cold reset */ | 632 | /* Sync reg_cache with the hardware after cold reset */ |
| @@ -647,8 +638,8 @@ static int wm9712_soc_resume(struct platform_device *pdev) | |||
| 647 | } | 638 | } |
| 648 | } | 639 | } |
| 649 | 640 | ||
| 650 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) | 641 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) |
| 651 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0); | 642 | wm9712_set_bias_level(codec, SND_SOC_BIAS_ON); |
| 652 | 643 | ||
| 653 | return ret; | 644 | return ret; |
| 654 | } | 645 | } |
| @@ -682,7 +673,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
| 682 | codec->num_dai = ARRAY_SIZE(wm9712_dai); | 673 | codec->num_dai = ARRAY_SIZE(wm9712_dai); |
| 683 | codec->write = ac97_write; | 674 | codec->write = ac97_write; |
| 684 | codec->read = ac97_read; | 675 | codec->read = ac97_read; |
| 685 | codec->dapm_event = wm9712_dapm_event; | 676 | codec->set_bias_level = wm9712_set_bias_level; |
| 686 | INIT_LIST_HEAD(&codec->dapm_widgets); | 677 | INIT_LIST_HEAD(&codec->dapm_widgets); |
| 687 | INIT_LIST_HEAD(&codec->dapm_paths); | 678 | INIT_LIST_HEAD(&codec->dapm_paths); |
| 688 | 679 | ||
| @@ -706,7 +697,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
| 706 | /* set alc mux to none */ | 697 | /* set alc mux to none */ |
| 707 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 698 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
| 708 | 699 | ||
| 709 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 700 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 710 | wm9712_add_controls(codec); | 701 | wm9712_add_controls(codec); |
| 711 | wm9712_add_widgets(codec); | 702 | wm9712_add_widgets(codec); |
| 712 | ret = snd_soc_register_card(socdev); | 703 | ret = snd_soc_register_card(socdev); |
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h index 719105d61e65..d29e8a18ca6d 100644 --- a/sound/soc/codecs/wm9712.h +++ b/sound/soc/codecs/wm9712.h | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #define WM9712_DAI_AC97_HIFI 0 | 8 | #define WM9712_DAI_AC97_HIFI 0 |
| 9 | #define WM9712_DAI_AC97_AUX 1 | 9 | #define WM9712_DAI_AC97_AUX 1 |
| 10 | 10 | ||
| 11 | extern struct snd_soc_codec_dai wm9712_dai[2]; | 11 | extern struct snd_soc_dai wm9712_dai[2]; |
| 12 | extern struct snd_soc_codec_device soc_codec_dev_wm9712; | 12 | extern struct snd_soc_codec_device soc_codec_dev_wm9712; |
| 13 | 13 | ||
| 14 | #endif | 14 | #endif |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 1f241161445c..38d1fe0971fc 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
| @@ -10,9 +10,6 @@ | |||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. | 11 | * option) any later version. |
| 12 | * | 12 | * |
| 13 | * Revision history | ||
| 14 | * 4th Feb 2006 Initial version. | ||
| 15 | * | ||
| 16 | * Features:- | 13 | * Features:- |
| 17 | * | 14 | * |
| 18 | * o Support for AC97 Codec, Voice DAC and Aux DAC | 15 | * o Support for AC97 Codec, Voice DAC and Aux DAC |
| @@ -456,7 +453,7 @@ SND_SOC_DAPM_INPUT("MIC2B"), | |||
| 456 | SND_SOC_DAPM_VMID("VMID"), | 453 | SND_SOC_DAPM_VMID("VMID"), |
| 457 | }; | 454 | }; |
| 458 | 455 | ||
| 459 | static const char *audio_map[][3] = { | 456 | static const struct snd_soc_dapm_route audio_map[] = { |
| 460 | /* left HP mixer */ | 457 | /* left HP mixer */ |
| 461 | {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, | 458 | {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, |
| 462 | {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, | 459 | {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, |
| @@ -607,21 +604,14 @@ static const char *audio_map[][3] = { | |||
| 607 | {"Capture Mono Mux", "Stereo", "Capture Mixer"}, | 604 | {"Capture Mono Mux", "Stereo", "Capture Mixer"}, |
| 608 | {"Capture Mono Mux", "Left", "Left Capture Source"}, | 605 | {"Capture Mono Mux", "Left", "Left Capture Source"}, |
| 609 | {"Capture Mono Mux", "Right", "Right Capture Source"}, | 606 | {"Capture Mono Mux", "Right", "Right Capture Source"}, |
| 610 | |||
| 611 | {NULL, NULL, NULL}, | ||
| 612 | }; | 607 | }; |
| 613 | 608 | ||
| 614 | static int wm9713_add_widgets(struct snd_soc_codec *codec) | 609 | static int wm9713_add_widgets(struct snd_soc_codec *codec) |
| 615 | { | 610 | { |
| 616 | int i; | 611 | snd_soc_dapm_new_controls(codec, wm9713_dapm_widgets, |
| 617 | 612 | ARRAY_SIZE(wm9713_dapm_widgets)); | |
| 618 | for (i = 0; i < ARRAY_SIZE(wm9713_dapm_widgets); i++) | ||
| 619 | snd_soc_dapm_new_control(codec, &wm9713_dapm_widgets[i]); | ||
| 620 | 613 | ||
| 621 | /* set up audio path audio_mapnects */ | 614 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 622 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
| 623 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 624 | audio_map[i][1], audio_map[i][2]); | ||
| 625 | 615 | ||
| 626 | snd_soc_dapm_new_widgets(codec); | 616 | snd_soc_dapm_new_widgets(codec); |
| 627 | return 0; | 617 | return 0; |
| @@ -799,7 +789,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
| 799 | return 0; | 789 | return 0; |
| 800 | } | 790 | } |
| 801 | 791 | ||
| 802 | static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | 792 | static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, |
| 803 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 793 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
| 804 | { | 794 | { |
| 805 | struct snd_soc_codec *codec = codec_dai->codec; | 795 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -810,7 +800,7 @@ static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | |||
| 810 | * Tristate the PCM DAI lines, tristate can be disabled by calling | 800 | * Tristate the PCM DAI lines, tristate can be disabled by calling |
| 811 | * wm9713_set_dai_fmt() | 801 | * wm9713_set_dai_fmt() |
| 812 | */ | 802 | */ |
| 813 | static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai, | 803 | static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai, |
| 814 | int tristate) | 804 | int tristate) |
| 815 | { | 805 | { |
| 816 | struct snd_soc_codec *codec = codec_dai->codec; | 806 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -826,7 +816,7 @@ static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai, | |||
| 826 | * Configure WM9713 clock dividers. | 816 | * Configure WM9713 clock dividers. |
| 827 | * Voice DAC needs 256 FS | 817 | * Voice DAC needs 256 FS |
| 828 | */ | 818 | */ |
| 829 | static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | 819 | static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
| 830 | int div_id, int div) | 820 | int div_id, int div) |
| 831 | { | 821 | { |
| 832 | struct snd_soc_codec *codec = codec_dai->codec; | 822 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -868,7 +858,7 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | |||
| 868 | return 0; | 858 | return 0; |
| 869 | } | 859 | } |
| 870 | 860 | ||
| 871 | static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 861 | static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, |
| 872 | unsigned int fmt) | 862 | unsigned int fmt) |
| 873 | { | 863 | { |
| 874 | struct snd_soc_codec *codec = codec_dai->codec; | 864 | struct snd_soc_codec *codec = codec_dai->codec; |
| @@ -886,7 +876,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
| 886 | gpio |= 0x0018; | 876 | gpio |= 0x0018; |
| 887 | break; | 877 | break; |
| 888 | case SND_SOC_DAIFMT_CBS_CFS: | 878 | case SND_SOC_DAIFMT_CBS_CFS: |
| 889 | reg |= 0x0200; | 879 | reg |= 0x2000; |
| 890 | gpio |= 0x001a; | 880 | gpio |= 0x001a; |
| 891 | break; | 881 | break; |
| 892 | case SND_SOC_DAIFMT_CBS_CFM: | 882 | case SND_SOC_DAIFMT_CBS_CFM: |
| @@ -1011,15 +1001,24 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) | |||
| 1011 | return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); | 1001 | return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); |
| 1012 | } | 1002 | } |
| 1013 | 1003 | ||
| 1014 | #define WM9713_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 1004 | #define WM9713_RATES (SNDRV_PCM_RATE_8000 | \ |
| 1015 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 1005 | SNDRV_PCM_RATE_11025 | \ |
| 1016 | SNDRV_PCM_RATE_48000) | 1006 | SNDRV_PCM_RATE_22050 | \ |
| 1007 | SNDRV_PCM_RATE_44100 | \ | ||
| 1008 | SNDRV_PCM_RATE_48000) | ||
| 1009 | |||
| 1010 | #define WM9713_PCM_RATES (SNDRV_PCM_RATE_8000 | \ | ||
| 1011 | SNDRV_PCM_RATE_11025 | \ | ||
| 1012 | SNDRV_PCM_RATE_16000 | \ | ||
| 1013 | SNDRV_PCM_RATE_22050 | \ | ||
| 1014 | SNDRV_PCM_RATE_44100 | \ | ||
| 1015 | SNDRV_PCM_RATE_48000) | ||
| 1017 | 1016 | ||
| 1018 | #define WM9713_PCM_FORMATS \ | 1017 | #define WM9713_PCM_FORMATS \ |
| 1019 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1018 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ |
| 1020 | SNDRV_PCM_FORMAT_S24_LE) | 1019 | SNDRV_PCM_FORMAT_S24_LE) |
| 1021 | 1020 | ||
| 1022 | struct snd_soc_codec_dai wm9713_dai[] = { | 1021 | struct snd_soc_dai wm9713_dai[] = { |
| 1023 | { | 1022 | { |
| 1024 | .name = "AC97 HiFi", | 1023 | .name = "AC97 HiFi", |
| 1025 | .type = SND_SOC_DAI_AC97_BUS, | 1024 | .type = SND_SOC_DAI_AC97_BUS, |
| @@ -1061,13 +1060,13 @@ struct snd_soc_codec_dai wm9713_dai[] = { | |||
| 1061 | .stream_name = "Voice Playback", | 1060 | .stream_name = "Voice Playback", |
| 1062 | .channels_min = 1, | 1061 | .channels_min = 1, |
| 1063 | .channels_max = 1, | 1062 | .channels_max = 1, |
| 1064 | .rates = WM9713_RATES, | 1063 | .rates = WM9713_PCM_RATES, |
| 1065 | .formats = WM9713_PCM_FORMATS,}, | 1064 | .formats = WM9713_PCM_FORMATS,}, |
| 1066 | .capture = { | 1065 | .capture = { |
| 1067 | .stream_name = "Voice Capture", | 1066 | .stream_name = "Voice Capture", |
| 1068 | .channels_min = 1, | 1067 | .channels_min = 1, |
| 1069 | .channels_max = 2, | 1068 | .channels_max = 2, |
| 1070 | .rates = WM9713_RATES, | 1069 | .rates = WM9713_PCM_RATES, |
| 1071 | .formats = WM9713_PCM_FORMATS,}, | 1070 | .formats = WM9713_PCM_FORMATS,}, |
| 1072 | .ops = { | 1071 | .ops = { |
| 1073 | .hw_params = wm9713_pcm_hw_params, | 1072 | .hw_params = wm9713_pcm_hw_params, |
| @@ -1086,44 +1085,44 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) | |||
| 1086 | { | 1085 | { |
| 1087 | if (try_warm && soc_ac97_ops.warm_reset) { | 1086 | if (try_warm && soc_ac97_ops.warm_reset) { |
| 1088 | soc_ac97_ops.warm_reset(codec->ac97); | 1087 | soc_ac97_ops.warm_reset(codec->ac97); |
| 1089 | if (!(ac97_read(codec, 0) & 0x8000)) | 1088 | if (ac97_read(codec, 0) == wm9713_reg[0]) |
| 1090 | return 1; | 1089 | return 1; |
| 1091 | } | 1090 | } |
| 1092 | 1091 | ||
| 1093 | soc_ac97_ops.reset(codec->ac97); | 1092 | soc_ac97_ops.reset(codec->ac97); |
| 1094 | if (ac97_read(codec, 0) & 0x8000) | 1093 | if (ac97_read(codec, 0) != wm9713_reg[0]) |
| 1095 | return -EIO; | 1094 | return -EIO; |
| 1096 | return 0; | 1095 | return 0; |
| 1097 | } | 1096 | } |
| 1098 | EXPORT_SYMBOL_GPL(wm9713_reset); | 1097 | EXPORT_SYMBOL_GPL(wm9713_reset); |
| 1099 | 1098 | ||
| 1100 | static int wm9713_dapm_event(struct snd_soc_codec *codec, int event) | 1099 | static int wm9713_set_bias_level(struct snd_soc_codec *codec, |
| 1100 | enum snd_soc_bias_level level) | ||
| 1101 | { | 1101 | { |
| 1102 | u16 reg; | 1102 | u16 reg; |
| 1103 | 1103 | ||
| 1104 | switch (event) { | 1104 | switch (level) { |
| 1105 | case SNDRV_CTL_POWER_D0: /* full On */ | 1105 | case SND_SOC_BIAS_ON: |
| 1106 | /* enable thermal shutdown */ | 1106 | /* enable thermal shutdown */ |
| 1107 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; | 1107 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; |
| 1108 | ac97_write(codec, AC97_EXTENDED_MID, reg); | 1108 | ac97_write(codec, AC97_EXTENDED_MID, reg); |
| 1109 | break; | 1109 | break; |
| 1110 | case SNDRV_CTL_POWER_D1: /* partial On */ | 1110 | case SND_SOC_BIAS_PREPARE: |
| 1111 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
| 1112 | break; | 1111 | break; |
| 1113 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 1112 | case SND_SOC_BIAS_STANDBY: |
| 1114 | /* enable master bias and vmid */ | 1113 | /* enable master bias and vmid */ |
| 1115 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; | 1114 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; |
| 1116 | ac97_write(codec, AC97_EXTENDED_MID, reg); | 1115 | ac97_write(codec, AC97_EXTENDED_MID, reg); |
| 1117 | ac97_write(codec, AC97_POWERDOWN, 0x0000); | 1116 | ac97_write(codec, AC97_POWERDOWN, 0x0000); |
| 1118 | break; | 1117 | break; |
| 1119 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 1118 | case SND_SOC_BIAS_OFF: |
| 1120 | /* disable everything including AC link */ | 1119 | /* disable everything including AC link */ |
| 1121 | ac97_write(codec, AC97_EXTENDED_MID, 0xffff); | 1120 | ac97_write(codec, AC97_EXTENDED_MID, 0xffff); |
| 1122 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); | 1121 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); |
| 1123 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 1122 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
| 1124 | break; | 1123 | break; |
| 1125 | } | 1124 | } |
| 1126 | codec->dapm_state = event; | 1125 | codec->bias_level = level; |
| 1127 | return 0; | 1126 | return 0; |
| 1128 | } | 1127 | } |
| 1129 | 1128 | ||
| @@ -1160,7 +1159,7 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
| 1160 | return ret; | 1159 | return ret; |
| 1161 | } | 1160 | } |
| 1162 | 1161 | ||
| 1163 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1162 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1164 | 1163 | ||
| 1165 | /* do we need to re-start the PLL ? */ | 1164 | /* do we need to re-start the PLL ? */ |
| 1166 | if (wm9713->pll_out) | 1165 | if (wm9713->pll_out) |
| @@ -1176,8 +1175,8 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
| 1176 | } | 1175 | } |
| 1177 | } | 1176 | } |
| 1178 | 1177 | ||
| 1179 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) | 1178 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) |
| 1180 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D0); | 1179 | wm9713_set_bias_level(codec, SND_SOC_BIAS_ON); |
| 1181 | 1180 | ||
| 1182 | return ret; | 1181 | return ret; |
| 1183 | } | 1182 | } |
| @@ -1216,7 +1215,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
| 1216 | codec->num_dai = ARRAY_SIZE(wm9713_dai); | 1215 | codec->num_dai = ARRAY_SIZE(wm9713_dai); |
| 1217 | codec->write = ac97_write; | 1216 | codec->write = ac97_write; |
| 1218 | codec->read = ac97_read; | 1217 | codec->read = ac97_read; |
| 1219 | codec->dapm_event = wm9713_dapm_event; | 1218 | codec->set_bias_level = wm9713_set_bias_level; |
| 1220 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1219 | INIT_LIST_HEAD(&codec->dapm_widgets); |
| 1221 | INIT_LIST_HEAD(&codec->dapm_paths); | 1220 | INIT_LIST_HEAD(&codec->dapm_paths); |
| 1222 | 1221 | ||
| @@ -1238,7 +1237,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
| 1238 | goto reset_err; | 1237 | goto reset_err; |
| 1239 | } | 1238 | } |
| 1240 | 1239 | ||
| 1241 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1240 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1242 | 1241 | ||
| 1243 | /* unmute the adc - move to kcontrol */ | 1242 | /* unmute the adc - move to kcontrol */ |
| 1244 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1243 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h index d357b6c8134b..63b8d81756e3 100644 --- a/sound/soc/codecs/wm9713.h +++ b/sound/soc/codecs/wm9713.h | |||
| @@ -46,7 +46,7 @@ | |||
| 46 | #define WM9713_DAI_PCM_VOICE 2 | 46 | #define WM9713_DAI_PCM_VOICE 2 |
| 47 | 47 | ||
| 48 | extern struct snd_soc_codec_device soc_codec_dev_wm9713; | 48 | extern struct snd_soc_codec_device soc_codec_dev_wm9713; |
| 49 | extern struct snd_soc_codec_dai wm9713_dai[3]; | 49 | extern struct snd_soc_dai wm9713_dai[3]; |
| 50 | 50 | ||
| 51 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm); | 51 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm); |
| 52 | 52 | ||
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 20680c551aab..8f7e33834902 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config SND_DAVINCI_SOC | 1 | config SND_DAVINCI_SOC |
| 2 | tristate "SoC Audio for the TI DAVINCI chip" | 2 | tristate "SoC Audio for the TI DAVINCI chip" |
| 3 | depends on ARCH_DAVINCI && SND_SOC | 3 | depends on ARCH_DAVINCI |
| 4 | help | 4 | help |
| 5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
| 6 | the DAVINCI AC97 or I2S interface. You will also need | 6 | the DAVINCI AC97 or I2S interface. You will also need |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index fcd165240333..5e2c306399ed 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
| @@ -33,24 +33,24 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
| 33 | struct snd_pcm_hw_params *params) | 33 | struct snd_pcm_hw_params *params) |
| 34 | { | 34 | { |
| 35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 36 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 36 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 37 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 37 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 38 | int ret = 0; | 38 | int ret = 0; |
| 39 | 39 | ||
| 40 | /* set codec DAI configuration */ | 40 | /* set codec DAI configuration */ |
| 41 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 41 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
| 42 | SND_SOC_DAIFMT_CBM_CFM); | 42 | SND_SOC_DAIFMT_CBM_CFM); |
| 43 | if (ret < 0) | 43 | if (ret < 0) |
| 44 | return ret; | 44 | return ret; |
| 45 | 45 | ||
| 46 | /* set cpu DAI configuration */ | 46 | /* set cpu DAI configuration */ |
| 47 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | | 47 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | |
| 48 | SND_SOC_DAIFMT_IB_NF); | 48 | SND_SOC_DAIFMT_IB_NF); |
| 49 | if (ret < 0) | 49 | if (ret < 0) |
| 50 | return ret; | 50 | return ret; |
| 51 | 51 | ||
| 52 | /* set the codec system clock */ | 52 | /* set the codec system clock */ |
| 53 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, | 53 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, |
| 54 | SND_SOC_CLOCK_OUT); | 54 | SND_SOC_CLOCK_OUT); |
| 55 | if (ret < 0) | 55 | if (ret < 0) |
| 56 | return ret; | 56 | return ret; |
| @@ -71,7 +71,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | /* davinci-evm machine audio_mapnections to the codec pins */ | 73 | /* davinci-evm machine audio_mapnections to the codec pins */ |
| 74 | static const char *audio_map[][3] = { | 74 | static const struct snd_soc_dapm_route audio_map[] = { |
| 75 | /* Headphone connected to HPLOUT, HPROUT */ | 75 | /* Headphone connected to HPLOUT, HPROUT */ |
| 76 | {"Headphone Jack", NULL, "HPLOUT"}, | 76 | {"Headphone Jack", NULL, "HPLOUT"}, |
| 77 | {"Headphone Jack", NULL, "HPROUT"}, | 77 | {"Headphone Jack", NULL, "HPROUT"}, |
| @@ -90,36 +90,30 @@ static const char *audio_map[][3] = { | |||
| 90 | {"LINE2L", NULL, "Line In"}, | 90 | {"LINE2L", NULL, "Line In"}, |
| 91 | {"LINE1R", NULL, "Line In"}, | 91 | {"LINE1R", NULL, "Line In"}, |
| 92 | {"LINE2R", NULL, "Line In"}, | 92 | {"LINE2R", NULL, "Line In"}, |
| 93 | |||
| 94 | {NULL, NULL, NULL}, | ||
| 95 | }; | 93 | }; |
| 96 | 94 | ||
| 97 | /* Logic for a aic3x as connected on a davinci-evm */ | 95 | /* Logic for a aic3x as connected on a davinci-evm */ |
| 98 | static int evm_aic3x_init(struct snd_soc_codec *codec) | 96 | static int evm_aic3x_init(struct snd_soc_codec *codec) |
| 99 | { | 97 | { |
| 100 | int i; | ||
| 101 | |||
| 102 | /* Add davinci-evm specific widgets */ | 98 | /* Add davinci-evm specific widgets */ |
| 103 | for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) | 99 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
| 104 | snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); | 100 | ARRAY_SIZE(aic3x_dapm_widgets)); |
| 105 | 101 | ||
| 106 | /* Set up davinci-evm specific audio path audio_map */ | 102 | /* Set up davinci-evm specific audio path audio_map */ |
| 107 | for (i = 0; audio_map[i][0] != NULL; i++) | 103 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 108 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 109 | audio_map[i][1], audio_map[i][2]); | ||
| 110 | 104 | ||
| 111 | /* not connected */ | 105 | /* not connected */ |
| 112 | snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0); | 106 | snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); |
| 113 | snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0); | 107 | snd_soc_dapm_disable_pin(codec, "HPLCOM"); |
| 114 | snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0); | 108 | snd_soc_dapm_disable_pin(codec, "HPRCOM"); |
| 115 | 109 | ||
| 116 | /* always connected */ | 110 | /* always connected */ |
| 117 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | 111 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
| 118 | snd_soc_dapm_set_endpoint(codec, "Line Out", 1); | 112 | snd_soc_dapm_enable_pin(codec, "Line Out"); |
| 119 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | 113 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
| 120 | snd_soc_dapm_set_endpoint(codec, "Line In", 1); | 114 | snd_soc_dapm_enable_pin(codec, "Line In"); |
| 121 | 115 | ||
| 122 | snd_soc_dapm_sync_endpoints(codec); | 116 | snd_soc_dapm_sync(codec); |
| 123 | 117 | ||
| 124 | return 0; | 118 | return 0; |
| 125 | } | 119 | } |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index c421774b33ee..5ebf1ff71c4c 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
| @@ -147,7 +147,7 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) | |||
| 147 | static int davinci_i2s_startup(struct snd_pcm_substream *substream) | 147 | static int davinci_i2s_startup(struct snd_pcm_substream *substream) |
| 148 | { | 148 | { |
| 149 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 149 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 150 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 150 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 151 | struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; | 151 | struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; |
| 152 | 152 | ||
| 153 | cpu_dai->dma_data = dev->dma_params[substream->stream]; | 153 | cpu_dai->dma_data = dev->dma_params[substream->stream]; |
| @@ -155,7 +155,7 @@ static int davinci_i2s_startup(struct snd_pcm_substream *substream) | |||
| 155 | return 0; | 155 | return 0; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | static int davinci_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 158 | static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
| 159 | unsigned int fmt) | 159 | unsigned int fmt) |
| 160 | { | 160 | { |
| 161 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | 161 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; |
| @@ -295,11 +295,12 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 295 | return ret; | 295 | return ret; |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | static int davinci_i2s_probe(struct platform_device *pdev) | 298 | static int davinci_i2s_probe(struct platform_device *pdev, |
| 299 | struct snd_soc_dai *dai) | ||
| 299 | { | 300 | { |
| 300 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 301 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 301 | struct snd_soc_machine *machine = socdev->machine; | 302 | struct snd_soc_machine *machine = socdev->machine; |
| 302 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; | 303 | struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; |
| 303 | struct davinci_mcbsp_dev *dev; | 304 | struct davinci_mcbsp_dev *dev; |
| 304 | struct resource *mem, *ioarea; | 305 | struct resource *mem, *ioarea; |
| 305 | struct evm_snd_platform_data *pdata; | 306 | struct evm_snd_platform_data *pdata; |
| @@ -356,11 +357,12 @@ err_release_region: | |||
| 356 | return ret; | 357 | return ret; |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 359 | static void davinci_i2s_remove(struct platform_device *pdev) | 360 | static void davinci_i2s_remove(struct platform_device *pdev, |
| 361 | struct snd_soc_dai *dai) | ||
| 360 | { | 362 | { |
| 361 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 363 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 362 | struct snd_soc_machine *machine = socdev->machine; | 364 | struct snd_soc_machine *machine = socdev->machine; |
| 363 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; | 365 | struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; |
| 364 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | 366 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; |
| 365 | struct resource *mem; | 367 | struct resource *mem; |
| 366 | 368 | ||
| @@ -376,7 +378,7 @@ static void davinci_i2s_remove(struct platform_device *pdev) | |||
| 376 | 378 | ||
| 377 | #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 | 379 | #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 |
| 378 | 380 | ||
| 379 | struct snd_soc_cpu_dai davinci_i2s_dai = { | 381 | struct snd_soc_dai davinci_i2s_dai = { |
| 380 | .name = "davinci-i2s", | 382 | .name = "davinci-i2s", |
| 381 | .id = 0, | 383 | .id = 0, |
| 382 | .type = SND_SOC_DAI_I2S, | 384 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h index 9592d17db320..c5b091807eec 100644 --- a/sound/soc/davinci/davinci-i2s.h +++ b/sound/soc/davinci/davinci-i2s.h | |||
| @@ -12,6 +12,6 @@ | |||
| 12 | #ifndef _DAVINCI_I2S_H | 12 | #ifndef _DAVINCI_I2S_H |
| 13 | #define _DAVINCI_I2S_H | 13 | #define _DAVINCI_I2S_H |
| 14 | 14 | ||
| 15 | extern struct snd_soc_cpu_dai davinci_i2s_dai; | 15 | extern struct snd_soc_dai davinci_i2s_dai; |
| 16 | 16 | ||
| 17 | #endif | 17 | #endif |
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 6a76927c9971..6a5e56a782bb 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
| @@ -350,7 +350,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) | |||
| 350 | static u64 davinci_pcm_dmamask = 0xffffffff; | 350 | static u64 davinci_pcm_dmamask = 0xffffffff; |
| 351 | 351 | ||
| 352 | static int davinci_pcm_new(struct snd_card *card, | 352 | static int davinci_pcm_new(struct snd_card *card, |
| 353 | struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) | 353 | struct snd_soc_dai *dai, struct snd_pcm *pcm) |
| 354 | { | 354 | { |
| 355 | int ret; | 355 | int ret; |
| 356 | 356 | ||
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 257101f44e9e..3368ace60977 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | menu "ALSA SoC audio for Freescale SOCs" | ||
| 2 | |||
| 3 | config SND_SOC_MPC8610 | 1 | config SND_SOC_MPC8610 |
| 4 | bool "ALSA SoC support for the MPC8610 SOC" | 2 | bool "ALSA SoC support for the MPC8610 SOC" |
| 5 | depends on SND_SOC && MPC8610_HPCD | 3 | depends on MPC8610_HPCD |
| 6 | default y if MPC8610 | 4 | default y if MPC8610 |
| 7 | help | 5 | help |
| 8 | Say Y if you want to add support for codecs attached to the SSI | 6 | Say Y if you want to add support for codecs attached to the SSI |
| @@ -16,5 +14,3 @@ config SND_SOC_MPC8610_HPCD | |||
| 16 | default y if MPC8610_HPCD | 14 | default y if MPC8610_HPCD |
| 17 | help | 15 | help |
| 18 | Say Y if you want to enable audio on the Freescale MPC8610 HPCD. | 16 | Say Y if you want to enable audio on the Freescale MPC8610 HPCD. |
| 19 | |||
| 20 | endmenu | ||
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 78de7168d2ba..da2bc5902864 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
| @@ -282,7 +282,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) | |||
| 282 | * once for each .dai_link in the machine driver's snd_soc_machine | 282 | * once for each .dai_link in the machine driver's snd_soc_machine |
| 283 | * structure. | 283 | * structure. |
| 284 | */ | 284 | */ |
| 285 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | 285 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, |
| 286 | struct snd_pcm *pcm) | 286 | struct snd_pcm *pcm) |
| 287 | { | 287 | { |
| 288 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(32); | 288 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(32); |
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h index 430a6ce8b0d0..385d4a42603c 100644 --- a/sound/soc/fsl/fsl_dma.h +++ b/sound/soc/fsl/fsl_dma.h | |||
| @@ -126,7 +126,7 @@ struct fsl_dma_link_descriptor { | |||
| 126 | u8 res[4]; /* Reserved */ | 126 | u8 res[4]; /* Reserved */ |
| 127 | } __attribute__ ((aligned(32), packed)); | 127 | } __attribute__ ((aligned(32), packed)); |
| 128 | 128 | ||
| 129 | /* DMA information needed to create a snd_soc_cpu_dai object | 129 | /* DMA information needed to create a snd_soc_dai object |
| 130 | * | 130 | * |
| 131 | * ssi_stx_phys: bus address of SSI STX register to use | 131 | * ssi_stx_phys: bus address of SSI STX register to use |
| 132 | * ssi_srx_phys: bus address of SSI SRX register to use | 132 | * ssi_srx_phys: bus address of SSI SRX register to use |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index f588545698f3..71bff33f5528 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
| @@ -82,7 +82,7 @@ struct fsl_ssi_private { | |||
| 82 | struct device *dev; | 82 | struct device *dev; |
| 83 | unsigned int playback; | 83 | unsigned int playback; |
| 84 | unsigned int capture; | 84 | unsigned int capture; |
| 85 | struct snd_soc_cpu_dai cpu_dai; | 85 | struct snd_soc_dai cpu_dai; |
| 86 | struct device_attribute dev_attr; | 86 | struct device_attribute dev_attr; |
| 87 | 87 | ||
| 88 | struct { | 88 | struct { |
| @@ -479,7 +479,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) | |||
| 479 | * @freq: the frequency of the given clock ID, currently ignored | 479 | * @freq: the frequency of the given clock ID, currently ignored |
| 480 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) | 480 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) |
| 481 | */ | 481 | */ |
| 482 | static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 482 | static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai, |
| 483 | int clk_id, unsigned int freq, int dir) | 483 | int clk_id, unsigned int freq, int dir) |
| 484 | { | 484 | { |
| 485 | 485 | ||
| @@ -497,7 +497,7 @@ static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
| 497 | * | 497 | * |
| 498 | * @format: one of SND_SOC_DAIFMT_xxx | 498 | * @format: one of SND_SOC_DAIFMT_xxx |
| 499 | */ | 499 | */ |
| 500 | static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format) | 500 | static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) |
| 501 | { | 501 | { |
| 502 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; | 502 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; |
| 503 | } | 503 | } |
| @@ -505,7 +505,7 @@ static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format) | |||
| 505 | /** | 505 | /** |
| 506 | * fsl_ssi_dai_template: template CPU DAI for the SSI | 506 | * fsl_ssi_dai_template: template CPU DAI for the SSI |
| 507 | */ | 507 | */ |
| 508 | static struct snd_soc_cpu_dai fsl_ssi_dai_template = { | 508 | static struct snd_soc_dai fsl_ssi_dai_template = { |
| 509 | .playback = { | 509 | .playback = { |
| 510 | /* The SSI does not support monaural audio. */ | 510 | /* The SSI does not support monaural audio. */ |
| 511 | .channels_min = 2, | 511 | .channels_min = 2, |
| @@ -569,15 +569,15 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev, | |||
| 569 | } | 569 | } |
| 570 | 570 | ||
| 571 | /** | 571 | /** |
| 572 | * fsl_ssi_create_dai: create a snd_soc_cpu_dai structure | 572 | * fsl_ssi_create_dai: create a snd_soc_dai structure |
| 573 | * | 573 | * |
| 574 | * This function is called by the machine driver to create a snd_soc_cpu_dai | 574 | * This function is called by the machine driver to create a snd_soc_dai |
| 575 | * structure. The function creates an ssi_private object, which contains | 575 | * structure. The function creates an ssi_private object, which contains |
| 576 | * the snd_soc_cpu_dai. It also creates the sysfs statistics device. | 576 | * the snd_soc_dai. It also creates the sysfs statistics device. |
| 577 | */ | 577 | */ |
| 578 | struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | 578 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) |
| 579 | { | 579 | { |
| 580 | struct snd_soc_cpu_dai *fsl_ssi_dai; | 580 | struct snd_soc_dai *fsl_ssi_dai; |
| 581 | struct fsl_ssi_private *ssi_private; | 581 | struct fsl_ssi_private *ssi_private; |
| 582 | int ret = 0; | 582 | int ret = 0; |
| 583 | struct device_attribute *dev_attr; | 583 | struct device_attribute *dev_attr; |
| @@ -588,7 +588,7 @@ struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | |||
| 588 | return NULL; | 588 | return NULL; |
| 589 | } | 589 | } |
| 590 | memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template, | 590 | memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template, |
| 591 | sizeof(struct snd_soc_cpu_dai)); | 591 | sizeof(struct snd_soc_dai)); |
| 592 | 592 | ||
| 593 | fsl_ssi_dai = &ssi_private->cpu_dai; | 593 | fsl_ssi_dai = &ssi_private->cpu_dai; |
| 594 | dev_attr = &ssi_private->dev_attr; | 594 | dev_attr = &ssi_private->dev_attr; |
| @@ -623,11 +623,11 @@ struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | |||
| 623 | EXPORT_SYMBOL_GPL(fsl_ssi_create_dai); | 623 | EXPORT_SYMBOL_GPL(fsl_ssi_create_dai); |
| 624 | 624 | ||
| 625 | /** | 625 | /** |
| 626 | * fsl_ssi_destroy_dai: destroy the snd_soc_cpu_dai object | 626 | * fsl_ssi_destroy_dai: destroy the snd_soc_dai object |
| 627 | * | 627 | * |
| 628 | * This function undoes the operations of fsl_ssi_create_dai() | 628 | * This function undoes the operations of fsl_ssi_create_dai() |
| 629 | */ | 629 | */ |
| 630 | void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai) | 630 | void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) |
| 631 | { | 631 | { |
| 632 | struct fsl_ssi_private *ssi_private = | 632 | struct fsl_ssi_private *ssi_private = |
| 633 | container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai); | 633 | container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai); |
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index c5ce88e15651..83b44d700e33 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h | |||
| @@ -217,8 +217,8 @@ struct fsl_ssi_info { | |||
| 217 | struct device *dev; | 217 | struct device *dev; |
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); | 220 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); |
| 221 | void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai); | 221 | void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai); |
| 222 | 222 | ||
| 223 | #endif | 223 | #endif |
| 224 | 224 | ||
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index a00aac7a71f1..4bdc9d8fc90e 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
| @@ -58,9 +58,9 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) | |||
| 58 | sound_device->dev.platform_data; | 58 | sound_device->dev.platform_data; |
| 59 | 59 | ||
| 60 | /* Program the signal routing between the SSI and the DMA */ | 60 | /* Program the signal routing between the SSI and the DMA */ |
| 61 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 61 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
| 62 | machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI); | 62 | machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI); |
| 63 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 63 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
| 64 | machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI); | 64 | machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI); |
| 65 | 65 | ||
| 66 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, | 66 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, |
| @@ -96,62 +96,52 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) | |||
| 96 | static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) | 96 | static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) |
| 97 | { | 97 | { |
| 98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 99 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 99 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 100 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 100 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 101 | struct mpc8610_hpcd_data *machine_data = | 101 | struct mpc8610_hpcd_data *machine_data = |
| 102 | rtd->socdev->dev->platform_data; | 102 | rtd->socdev->dev->platform_data; |
| 103 | int ret = 0; | 103 | int ret = 0; |
| 104 | 104 | ||
| 105 | /* Tell the CPU driver what the serial protocol is. */ | 105 | /* Tell the CPU driver what the serial protocol is. */ |
| 106 | if (cpu_dai->dai_ops.set_fmt) { | 106 | ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format); |
| 107 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, | 107 | if (ret < 0) { |
| 108 | machine_data->dai_format); | 108 | dev_err(substream->pcm->card->dev, |
| 109 | if (ret < 0) { | 109 | "could not set CPU driver audio format\n"); |
| 110 | dev_err(substream->pcm->card->dev, | 110 | return ret; |
| 111 | "could not set CPU driver audio format\n"); | ||
| 112 | return ret; | ||
| 113 | } | ||
| 114 | } | 111 | } |
| 115 | 112 | ||
| 116 | /* Tell the codec driver what the serial protocol is. */ | 113 | /* Tell the codec driver what the serial protocol is. */ |
| 117 | if (codec_dai->dai_ops.set_fmt) { | 114 | ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format); |
| 118 | ret = codec_dai->dai_ops.set_fmt(codec_dai, | 115 | if (ret < 0) { |
| 119 | machine_data->dai_format); | 116 | dev_err(substream->pcm->card->dev, |
| 120 | if (ret < 0) { | 117 | "could not set codec driver audio format\n"); |
| 121 | dev_err(substream->pcm->card->dev, | 118 | return ret; |
| 122 | "could not set codec driver audio format\n"); | ||
| 123 | return ret; | ||
| 124 | } | ||
| 125 | } | 119 | } |
| 126 | 120 | ||
| 127 | /* | 121 | /* |
| 128 | * Tell the CPU driver what the clock frequency is, and whether it's a | 122 | * Tell the CPU driver what the clock frequency is, and whether it's a |
| 129 | * slave or master. | 123 | * slave or master. |
| 130 | */ | 124 | */ |
| 131 | if (cpu_dai->dai_ops.set_sysclk) { | 125 | ret = snd_soc_dai_set_sysclk(cpu_dai, 0, |
| 132 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0, | 126 | machine_data->clk_frequency, |
| 133 | machine_data->clk_frequency, | 127 | machine_data->cpu_clk_direction); |
| 134 | machine_data->cpu_clk_direction); | 128 | if (ret < 0) { |
| 135 | if (ret < 0) { | 129 | dev_err(substream->pcm->card->dev, |
| 136 | dev_err(substream->pcm->card->dev, | 130 | "could not set CPU driver clock parameters\n"); |
| 137 | "could not set CPU driver clock parameters\n"); | 131 | return ret; |
| 138 | return ret; | ||
| 139 | } | ||
| 140 | } | 132 | } |
| 141 | 133 | ||
| 142 | /* | 134 | /* |
| 143 | * Tell the codec driver what the MCLK frequency is, and whether it's | 135 | * Tell the codec driver what the MCLK frequency is, and whether it's |
| 144 | * a slave or master. | 136 | * a slave or master. |
| 145 | */ | 137 | */ |
| 146 | if (codec_dai->dai_ops.set_sysclk) { | 138 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, |
| 147 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, | 139 | machine_data->clk_frequency, |
| 148 | machine_data->clk_frequency, | 140 | machine_data->codec_clk_direction); |
| 149 | machine_data->codec_clk_direction); | 141 | if (ret < 0) { |
| 150 | if (ret < 0) { | 142 | dev_err(substream->pcm->card->dev, |
| 151 | dev_err(substream->pcm->card->dev, | 143 | "could not set codec driver clock params\n"); |
| 152 | "could not set codec driver clock params\n"); | 144 | return ret; |
| 153 | return ret; | ||
| 154 | } | ||
| 155 | } | 145 | } |
| 156 | 146 | ||
| 157 | return 0; | 147 | return 0; |
| @@ -170,9 +160,9 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) | |||
| 170 | 160 | ||
| 171 | /* Restore the signal routing */ | 161 | /* Restore the signal routing */ |
| 172 | 162 | ||
| 173 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 163 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
| 174 | machine_data->dma_channel_id[0], 0); | 164 | machine_data->dma_channel_id[0], 0); |
| 175 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 165 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
| 176 | machine_data->dma_channel_id[1], 0); | 166 | machine_data->dma_channel_id[1], 0); |
| 177 | 167 | ||
| 178 | switch (machine_data->ssi_id) { | 168 | switch (machine_data->ssi_id) { |
| @@ -182,7 +172,7 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) | |||
| 182 | break; | 172 | break; |
| 183 | case 1: | 173 | case 1: |
| 184 | clrsetbits_be32(&machine_data->guts->pmuxcr, | 174 | clrsetbits_be32(&machine_data->guts->pmuxcr, |
| 185 | CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); | 175 | CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA); |
| 186 | break; | 176 | break; |
| 187 | } | 177 | } |
| 188 | 178 | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 0230d83e8e5e..aea27e70043c 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
| @@ -1,5 +1,3 @@ | |||
| 1 | menu "SoC Audio for the Texas Instruments OMAP" | ||
| 2 | |||
| 3 | config SND_OMAP_SOC | 1 | config SND_OMAP_SOC |
| 4 | tristate "SoC Audio for the Texas Instruments OMAP chips" | 2 | tristate "SoC Audio for the Texas Instruments OMAP chips" |
| 5 | depends on ARCH_OMAP && SND_SOC | 3 | depends on ARCH_OMAP && SND_SOC |
| @@ -15,5 +13,3 @@ config SND_OMAP_SOC_N810 | |||
| 15 | select SND_SOC_TLV320AIC3X | 13 | select SND_SOC_TLV320AIC3X |
| 16 | help | 14 | help |
| 17 | Say Y if you want to add support for SoC audio on Nokia N810. | 15 | Say Y if you want to add support for SoC audio on Nokia N810. |
| 18 | |||
| 19 | endmenu | ||
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 6533563a6011..02cec96859b8 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
| @@ -30,15 +30,15 @@ | |||
| 30 | 30 | ||
| 31 | #include <asm/mach-types.h> | 31 | #include <asm/mach-types.h> |
| 32 | #include <asm/arch/hardware.h> | 32 | #include <asm/arch/hardware.h> |
| 33 | #include <asm/arch/gpio.h> | 33 | #include <linux/gpio.h> |
| 34 | #include <asm/arch/mcbsp.h> | 34 | #include <asm/arch/mcbsp.h> |
| 35 | 35 | ||
| 36 | #include "omap-mcbsp.h" | 36 | #include "omap-mcbsp.h" |
| 37 | #include "omap-pcm.h" | 37 | #include "omap-pcm.h" |
| 38 | #include "../codecs/tlv320aic3x.h" | 38 | #include "../codecs/tlv320aic3x.h" |
| 39 | 39 | ||
| 40 | #define RX44_HEADSET_AMP_GPIO 10 | 40 | #define N810_HEADSET_AMP_GPIO 10 |
| 41 | #define RX44_SPEAKER_AMP_GPIO 101 | 41 | #define N810_SPEAKER_AMP_GPIO 101 |
| 42 | 42 | ||
| 43 | static struct clk *sys_clkout2; | 43 | static struct clk *sys_clkout2; |
| 44 | static struct clk *sys_clkout2_src; | 44 | static struct clk *sys_clkout2_src; |
| @@ -46,13 +46,26 @@ static struct clk *func96m_clk; | |||
| 46 | 46 | ||
| 47 | static int n810_spk_func; | 47 | static int n810_spk_func; |
| 48 | static int n810_jack_func; | 48 | static int n810_jack_func; |
| 49 | static int n810_dmic_func; | ||
| 49 | 50 | ||
| 50 | static void n810_ext_control(struct snd_soc_codec *codec) | 51 | static void n810_ext_control(struct snd_soc_codec *codec) |
| 51 | { | 52 | { |
| 52 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", n810_spk_func); | 53 | if (n810_spk_func) |
| 53 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", n810_jack_func); | 54 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
| 55 | else | ||
| 56 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); | ||
| 57 | |||
| 58 | if (n810_jack_func) | ||
| 59 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
| 60 | else | ||
| 61 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
| 54 | 62 | ||
| 55 | snd_soc_dapm_sync_endpoints(codec); | 63 | if (n810_dmic_func) |
| 64 | snd_soc_dapm_enable_pin(codec, "DMic"); | ||
| 65 | else | ||
| 66 | snd_soc_dapm_disable_pin(codec, "DMic"); | ||
| 67 | |||
| 68 | snd_soc_dapm_sync(codec); | ||
| 56 | } | 69 | } |
| 57 | 70 | ||
| 58 | static int n810_startup(struct snd_pcm_substream *substream) | 71 | static int n810_startup(struct snd_pcm_substream *substream) |
| @@ -73,12 +86,12 @@ static int n810_hw_params(struct snd_pcm_substream *substream, | |||
| 73 | struct snd_pcm_hw_params *params) | 86 | struct snd_pcm_hw_params *params) |
| 74 | { | 87 | { |
| 75 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 88 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 76 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 89 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 77 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 90 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 78 | int err; | 91 | int err; |
| 79 | 92 | ||
| 80 | /* Set codec DAI configuration */ | 93 | /* Set codec DAI configuration */ |
| 81 | err = codec_dai->dai_ops.set_fmt(codec_dai, | 94 | err = snd_soc_dai_set_fmt(codec_dai, |
| 82 | SND_SOC_DAIFMT_I2S | | 95 | SND_SOC_DAIFMT_I2S | |
| 83 | SND_SOC_DAIFMT_NB_NF | | 96 | SND_SOC_DAIFMT_NB_NF | |
| 84 | SND_SOC_DAIFMT_CBM_CFM); | 97 | SND_SOC_DAIFMT_CBM_CFM); |
| @@ -86,7 +99,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream, | |||
| 86 | return err; | 99 | return err; |
| 87 | 100 | ||
| 88 | /* Set cpu DAI configuration */ | 101 | /* Set cpu DAI configuration */ |
| 89 | err = cpu_dai->dai_ops.set_fmt(cpu_dai, | 102 | err = snd_soc_dai_set_fmt(cpu_dai, |
| 90 | SND_SOC_DAIFMT_I2S | | 103 | SND_SOC_DAIFMT_I2S | |
| 91 | SND_SOC_DAIFMT_NB_NF | | 104 | SND_SOC_DAIFMT_NB_NF | |
| 92 | SND_SOC_DAIFMT_CBM_CFM); | 105 | SND_SOC_DAIFMT_CBM_CFM); |
| @@ -94,7 +107,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream, | |||
| 94 | return err; | 107 | return err; |
| 95 | 108 | ||
| 96 | /* Set the codec system clock for DAC and ADC */ | 109 | /* Set the codec system clock for DAC and ADC */ |
| 97 | err = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 12000000, | 110 | err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, |
| 98 | SND_SOC_CLOCK_IN); | 111 | SND_SOC_CLOCK_IN); |
| 99 | 112 | ||
| 100 | return err; | 113 | return err; |
| @@ -150,13 +163,35 @@ static int n810_set_jack(struct snd_kcontrol *kcontrol, | |||
| 150 | return 1; | 163 | return 1; |
| 151 | } | 164 | } |
| 152 | 165 | ||
| 166 | static int n810_get_input(struct snd_kcontrol *kcontrol, | ||
| 167 | struct snd_ctl_elem_value *ucontrol) | ||
| 168 | { | ||
| 169 | ucontrol->value.integer.value[0] = n810_dmic_func; | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static int n810_set_input(struct snd_kcontrol *kcontrol, | ||
| 175 | struct snd_ctl_elem_value *ucontrol) | ||
| 176 | { | ||
| 177 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 178 | |||
| 179 | if (n810_dmic_func == ucontrol->value.integer.value[0]) | ||
| 180 | return 0; | ||
| 181 | |||
| 182 | n810_dmic_func = ucontrol->value.integer.value[0]; | ||
| 183 | n810_ext_control(codec); | ||
| 184 | |||
| 185 | return 1; | ||
| 186 | } | ||
| 187 | |||
| 153 | static int n810_spk_event(struct snd_soc_dapm_widget *w, | 188 | static int n810_spk_event(struct snd_soc_dapm_widget *w, |
| 154 | struct snd_kcontrol *k, int event) | 189 | struct snd_kcontrol *k, int event) |
| 155 | { | 190 | { |
| 156 | if (SND_SOC_DAPM_EVENT_ON(event)) | 191 | if (SND_SOC_DAPM_EVENT_ON(event)) |
| 157 | omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 1); | 192 | gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); |
| 158 | else | 193 | else |
| 159 | omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 0); | 194 | gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); |
| 160 | 195 | ||
| 161 | return 0; | 196 | return 0; |
| 162 | } | 197 | } |
| @@ -165,9 +200,9 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w, | |||
| 165 | struct snd_kcontrol *k, int event) | 200 | struct snd_kcontrol *k, int event) |
| 166 | { | 201 | { |
| 167 | if (SND_SOC_DAPM_EVENT_ON(event)) | 202 | if (SND_SOC_DAPM_EVENT_ON(event)) |
| 168 | omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 1); | 203 | gpio_set_value(N810_HEADSET_AMP_GPIO, 1); |
| 169 | else | 204 | else |
| 170 | omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 0); | 205 | gpio_set_value(N810_HEADSET_AMP_GPIO, 0); |
| 171 | 206 | ||
| 172 | return 0; | 207 | return 0; |
| 173 | } | 208 | } |
| @@ -175,21 +210,27 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w, | |||
| 175 | static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { | 210 | static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { |
| 176 | SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), | 211 | SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), |
| 177 | SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), | 212 | SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), |
| 213 | SND_SOC_DAPM_MIC("DMic", NULL), | ||
| 178 | }; | 214 | }; |
| 179 | 215 | ||
| 180 | static const char *audio_map[][3] = { | 216 | static const struct snd_soc_dapm_route audio_map[] = { |
| 181 | {"Headphone Jack", NULL, "HPLOUT"}, | 217 | {"Headphone Jack", NULL, "HPLOUT"}, |
| 182 | {"Headphone Jack", NULL, "HPROUT"}, | 218 | {"Headphone Jack", NULL, "HPROUT"}, |
| 183 | 219 | ||
| 184 | {"Ext Spk", NULL, "LLOUT"}, | 220 | {"Ext Spk", NULL, "LLOUT"}, |
| 185 | {"Ext Spk", NULL, "RLOUT"}, | 221 | {"Ext Spk", NULL, "RLOUT"}, |
| 222 | |||
| 223 | {"DMic Rate 64", NULL, "Mic Bias 2V"}, | ||
| 224 | {"Mic Bias 2V", NULL, "DMic"}, | ||
| 186 | }; | 225 | }; |
| 187 | 226 | ||
| 188 | static const char *spk_function[] = {"Off", "On"}; | 227 | static const char *spk_function[] = {"Off", "On"}; |
| 189 | static const char *jack_function[] = {"Off", "Headphone"}; | 228 | static const char *jack_function[] = {"Off", "Headphone"}; |
| 229 | static const char *input_function[] = {"ADC", "Digital Mic"}; | ||
| 190 | static const struct soc_enum n810_enum[] = { | 230 | static const struct soc_enum n810_enum[] = { |
| 191 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | 231 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), |
| 192 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), | 232 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), |
| 233 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), | ||
| 193 | }; | 234 | }; |
| 194 | 235 | ||
| 195 | static const struct snd_kcontrol_new aic33_n810_controls[] = { | 236 | static const struct snd_kcontrol_new aic33_n810_controls[] = { |
| @@ -197,6 +238,8 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = { | |||
| 197 | n810_get_spk, n810_set_spk), | 238 | n810_get_spk, n810_set_spk), |
| 198 | SOC_ENUM_EXT("Jack Function", n810_enum[1], | 239 | SOC_ENUM_EXT("Jack Function", n810_enum[1], |
| 199 | n810_get_jack, n810_set_jack), | 240 | n810_get_jack, n810_set_jack), |
| 241 | SOC_ENUM_EXT("Input Select", n810_enum[2], | ||
| 242 | n810_get_input, n810_set_input), | ||
| 200 | }; | 243 | }; |
| 201 | 244 | ||
| 202 | static int n810_aic33_init(struct snd_soc_codec *codec) | 245 | static int n810_aic33_init(struct snd_soc_codec *codec) |
| @@ -204,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec) | |||
| 204 | int i, err; | 247 | int i, err; |
| 205 | 248 | ||
| 206 | /* Not connected */ | 249 | /* Not connected */ |
| 207 | snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0); | 250 | snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); |
| 208 | snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0); | 251 | snd_soc_dapm_disable_pin(codec, "HPLCOM"); |
| 209 | snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0); | 252 | snd_soc_dapm_disable_pin(codec, "HPRCOM"); |
| 210 | 253 | ||
| 211 | /* Add N810 specific controls */ | 254 | /* Add N810 specific controls */ |
| 212 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { | 255 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { |
| @@ -217,15 +260,13 @@ static int n810_aic33_init(struct snd_soc_codec *codec) | |||
| 217 | } | 260 | } |
| 218 | 261 | ||
| 219 | /* Add N810 specific widgets */ | 262 | /* Add N810 specific widgets */ |
| 220 | for (i = 0; i < ARRAY_SIZE(aic33_dapm_widgets); i++) | 263 | snd_soc_dapm_new_controls(codec, aic33_dapm_widgets, |
| 221 | snd_soc_dapm_new_control(codec, &aic33_dapm_widgets[i]); | 264 | ARRAY_SIZE(aic33_dapm_widgets)); |
| 222 | 265 | ||
| 223 | /* Set up N810 specific audio path audio_map */ | 266 | /* Set up N810 specific audio path audio_map */ |
| 224 | for (i = 0; i < ARRAY_SIZE(audio_map); i++) | 267 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 225 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 226 | audio_map[i][1], audio_map[i][2]); | ||
| 227 | 268 | ||
| 228 | snd_soc_dapm_sync_endpoints(codec); | 269 | snd_soc_dapm_sync(codec); |
| 229 | 270 | ||
| 230 | return 0; | 271 | return 0; |
| 231 | } | 272 | } |
| @@ -250,6 +291,8 @@ static struct snd_soc_machine snd_soc_machine_n810 = { | |||
| 250 | /* Audio private data */ | 291 | /* Audio private data */ |
| 251 | static struct aic3x_setup_data n810_aic33_setup = { | 292 | static struct aic3x_setup_data n810_aic33_setup = { |
| 252 | .i2c_address = 0x18, | 293 | .i2c_address = 0x18, |
| 294 | .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, | ||
| 295 | .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, | ||
| 253 | }; | 296 | }; |
| 254 | 297 | ||
| 255 | /* Audio subsystem */ | 298 | /* Audio subsystem */ |
| @@ -267,7 +310,7 @@ static int __init n810_soc_init(void) | |||
| 267 | int err; | 310 | int err; |
| 268 | struct device *dev; | 311 | struct device *dev; |
| 269 | 312 | ||
| 270 | if (!machine_is_nokia_n810()) | 313 | if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) |
| 271 | return -ENODEV; | 314 | return -ENODEV; |
| 272 | 315 | ||
| 273 | n810_snd_device = platform_device_alloc("soc-audio", -1); | 316 | n810_snd_device = platform_device_alloc("soc-audio", -1); |
| @@ -305,12 +348,12 @@ static int __init n810_soc_init(void) | |||
| 305 | clk_set_parent(sys_clkout2_src, func96m_clk); | 348 | clk_set_parent(sys_clkout2_src, func96m_clk); |
| 306 | clk_set_rate(sys_clkout2, 12000000); | 349 | clk_set_rate(sys_clkout2, 12000000); |
| 307 | 350 | ||
| 308 | if (omap_request_gpio(RX44_HEADSET_AMP_GPIO) < 0) | 351 | if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) |
| 309 | BUG(); | 352 | BUG(); |
| 310 | if (omap_request_gpio(RX44_SPEAKER_AMP_GPIO) < 0) | 353 | if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0) |
| 311 | BUG(); | 354 | BUG(); |
| 312 | omap_set_gpio_direction(RX44_HEADSET_AMP_GPIO, 0); | 355 | gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); |
| 313 | omap_set_gpio_direction(RX44_SPEAKER_AMP_GPIO, 0); | 356 | gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); |
| 314 | 357 | ||
| 315 | return 0; | 358 | return 0; |
| 316 | err2: | 359 | err2: |
| @@ -325,6 +368,9 @@ err1: | |||
| 325 | 368 | ||
| 326 | static void __exit n810_soc_exit(void) | 369 | static void __exit n810_soc_exit(void) |
| 327 | { | 370 | { |
| 371 | gpio_free(N810_SPEAKER_AMP_GPIO); | ||
| 372 | gpio_free(N810_HEADSET_AMP_GPIO); | ||
| 373 | |||
| 328 | platform_device_unregister(n810_snd_device); | 374 | platform_device_unregister(n810_snd_device); |
| 329 | } | 375 | } |
| 330 | 376 | ||
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 40d87e6d0de8..00b0c9d73cd4 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
| @@ -103,7 +103,7 @@ static const unsigned long omap2420_mcbsp_port[][2] = {}; | |||
| 103 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) | 103 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) |
| 104 | { | 104 | { |
| 105 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 105 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 106 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 106 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 107 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 107 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
| 108 | int err = 0; | 108 | int err = 0; |
| 109 | 109 | ||
| @@ -116,7 +116,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) | |||
| 116 | static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) | 116 | static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) |
| 117 | { | 117 | { |
| 118 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 118 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 119 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 119 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 120 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 120 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
| 121 | 121 | ||
| 122 | if (!cpu_dai->active) { | 122 | if (!cpu_dai->active) { |
| @@ -128,7 +128,7 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) | |||
| 128 | static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) | 128 | static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) |
| 129 | { | 129 | { |
| 130 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 130 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 131 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 131 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 132 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 132 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
| 133 | int err = 0; | 133 | int err = 0; |
| 134 | 134 | ||
| @@ -157,7 +157,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
| 157 | struct snd_pcm_hw_params *params) | 157 | struct snd_pcm_hw_params *params) |
| 158 | { | 158 | { |
| 159 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 159 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 160 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 160 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 161 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 161 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
| 162 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; | 162 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; |
| 163 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; | 163 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; |
| @@ -223,7 +223,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
| 223 | * This must be called before _set_clkdiv and _set_sysclk since McBSP register | 223 | * This must be called before _set_clkdiv and _set_sysclk since McBSP register |
| 224 | * cache is initialized here | 224 | * cache is initialized here |
| 225 | */ | 225 | */ |
| 226 | static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 226 | static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
| 227 | unsigned int fmt) | 227 | unsigned int fmt) |
| 228 | { | 228 | { |
| 229 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 229 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
| @@ -292,7 +292,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | |||
| 292 | return 0; | 292 | return 0; |
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 295 | static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, |
| 296 | int div_id, int div) | 296 | int div_id, int div) |
| 297 | { | 297 | { |
| 298 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 298 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
| @@ -347,7 +347,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
| 347 | return 0; | 347 | return 0; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 350 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
| 351 | int clk_id, unsigned int freq, | 351 | int clk_id, unsigned int freq, |
| 352 | int dir) | 352 | int dir) |
| 353 | { | 353 | { |
| @@ -376,7 +376,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
| 376 | return err; | 376 | return err; |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS] = { | 379 | struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = { |
| 380 | { | 380 | { |
| 381 | .name = "omap-mcbsp-dai", | 381 | .name = "omap-mcbsp-dai", |
| 382 | .id = 0, | 382 | .id = 0, |
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index 9965fd4b0427..ed8afb550671 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h | |||
| @@ -44,6 +44,6 @@ enum omap_mcbsp_div { | |||
| 44 | */ | 44 | */ |
| 45 | #define NUM_LINKS 1 | 45 | #define NUM_LINKS 1 |
| 46 | 46 | ||
| 47 | extern struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS]; | 47 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; |
| 48 | 48 | ||
| 49 | #endif | 49 | #endif |
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 62370202c649..e092f3d836d0 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
| @@ -316,7 +316,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
| 316 | } | 316 | } |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | int omap_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | 319 | int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
| 320 | struct snd_pcm *pcm) | 320 | struct snd_pcm *pcm) |
| 321 | { | 321 | { |
| 322 | int ret = 0; | 322 | int ret = 0; |
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 484f883459e0..12f6ac99b04c 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config SND_PXA2XX_SOC | 1 | config SND_PXA2XX_SOC |
| 2 | tristate "SoC Audio for the Intel PXA2xx chip" | 2 | tristate "SoC Audio for the Intel PXA2xx chip" |
| 3 | depends on ARCH_PXA && SND_SOC | 3 | depends on ARCH_PXA |
| 4 | help | 4 | help |
| 5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
| 6 | the PXA2xx AC97, I2S or SSP interface. You will also need | 6 | the PXA2xx AC97, I2S or SSP interface. You will also need |
| @@ -62,3 +62,12 @@ config SND_PXA2XX_SOC_E800 | |||
| 62 | help | 62 | help |
| 63 | Say Y if you want to add support for SoC audio on the | 63 | Say Y if you want to add support for SoC audio on the |
| 64 | Toshiba e800 PDA | 64 | Toshiba e800 PDA |
| 65 | |||
| 66 | config SND_PXA2XX_SOC_EM_X270 | ||
| 67 | tristate "SoC Audio support for CompuLab EM-x270" | ||
| 68 | depends on SND_PXA2XX_SOC && MACH_EM_X270 | ||
| 69 | select SND_PXA2XX_SOC_AC97 | ||
| 70 | select SND_SOC_WM9712 | ||
| 71 | help | ||
| 72 | Say Y if you want to add support for SoC audio on | ||
| 73 | CompuLab EM-x270. | ||
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 04e5646f75ba..5bc8edf9dca9 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile | |||
| @@ -13,10 +13,11 @@ snd-soc-poodle-objs := poodle.o | |||
| 13 | snd-soc-tosa-objs := tosa.o | 13 | snd-soc-tosa-objs := tosa.o |
| 14 | snd-soc-e800-objs := e800_wm9712.o | 14 | snd-soc-e800-objs := e800_wm9712.o |
| 15 | snd-soc-spitz-objs := spitz.o | 15 | snd-soc-spitz-objs := spitz.o |
| 16 | snd-soc-em-x270-objs := em-x270.o | ||
| 16 | 17 | ||
| 17 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o | 18 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o |
| 18 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o | 19 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o |
| 19 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o | 20 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o |
| 20 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o | 21 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o |
| 21 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o | 22 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o |
| 22 | 23 | obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o | |
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 7f32a1167572..c0294464a23a 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
| @@ -11,10 +11,6 @@ | |||
| 11 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
| 12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
| 13 | * option) any later version. | 13 | * option) any later version. |
| 14 | * | ||
| 15 | * Revision history | ||
| 16 | * 30th Nov 2005 Initial version. | ||
| 17 | * | ||
| 18 | */ | 14 | */ |
| 19 | 15 | ||
| 20 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| @@ -54,47 +50,51 @@ static int corgi_spk_func; | |||
| 54 | 50 | ||
| 55 | static void corgi_ext_control(struct snd_soc_codec *codec) | 51 | static void corgi_ext_control(struct snd_soc_codec *codec) |
| 56 | { | 52 | { |
| 57 | int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; | ||
| 58 | |||
| 59 | /* set up jack connection */ | 53 | /* set up jack connection */ |
| 60 | switch (corgi_jack_func) { | 54 | switch (corgi_jack_func) { |
| 61 | case CORGI_HP: | 55 | case CORGI_HP: |
| 62 | hp = 1; | ||
| 63 | /* set = unmute headphone */ | 56 | /* set = unmute headphone */ |
| 64 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 57 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
| 65 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 58 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
| 59 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | ||
| 60 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | ||
| 61 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
| 62 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
| 66 | break; | 63 | break; |
| 67 | case CORGI_MIC: | 64 | case CORGI_MIC: |
| 68 | mic = 1; | ||
| 69 | /* reset = mute headphone */ | 65 | /* reset = mute headphone */ |
| 70 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 66 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
| 71 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 67 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
| 68 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
| 69 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | ||
| 70 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
| 71 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
| 72 | break; | 72 | break; |
| 73 | case CORGI_LINE: | 73 | case CORGI_LINE: |
| 74 | line = 1; | ||
| 75 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 74 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
| 76 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 75 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
| 76 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | ||
| 77 | snd_soc_dapm_enable_pin(codec, "Line Jack"); | ||
| 78 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
| 79 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
| 77 | break; | 80 | break; |
| 78 | case CORGI_HEADSET: | 81 | case CORGI_HEADSET: |
| 79 | hs = 1; | ||
| 80 | mic = 1; | ||
| 81 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 82 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
| 82 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 83 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
| 84 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
| 85 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | ||
| 86 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
| 87 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); | ||
| 83 | break; | 88 | break; |
| 84 | } | 89 | } |
| 85 | 90 | ||
| 86 | if (corgi_spk_func == CORGI_SPK_ON) | 91 | if (corgi_spk_func == CORGI_SPK_ON) |
| 87 | spk = 1; | 92 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
| 88 | 93 | else | |
| 89 | /* set the enpoints to their new connetion states */ | 94 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); |
| 90 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); | ||
| 91 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic); | ||
| 92 | snd_soc_dapm_set_endpoint(codec, "Line Jack", line); | ||
| 93 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); | ||
| 94 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); | ||
| 95 | 95 | ||
| 96 | /* signal a DAPM event */ | 96 | /* signal a DAPM event */ |
| 97 | snd_soc_dapm_sync_endpoints(codec); | 97 | snd_soc_dapm_sync(codec); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | static int corgi_startup(struct snd_pcm_substream *substream) | 100 | static int corgi_startup(struct snd_pcm_substream *substream) |
| @@ -123,8 +123,8 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, | |||
| 123 | struct snd_pcm_hw_params *params) | 123 | struct snd_pcm_hw_params *params) |
| 124 | { | 124 | { |
| 125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 126 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 126 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 127 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 127 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 128 | unsigned int clk = 0; | 128 | unsigned int clk = 0; |
| 129 | int ret = 0; | 129 | int ret = 0; |
| 130 | 130 | ||
| @@ -143,25 +143,25 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, | |||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | /* set codec DAI configuration */ | 145 | /* set codec DAI configuration */ |
| 146 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 146 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
| 147 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 147 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 148 | if (ret < 0) | 148 | if (ret < 0) |
| 149 | return ret; | 149 | return ret; |
| 150 | 150 | ||
| 151 | /* set cpu DAI configuration */ | 151 | /* set cpu DAI configuration */ |
| 152 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 152 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
| 153 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 153 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 154 | if (ret < 0) | 154 | if (ret < 0) |
| 155 | return ret; | 155 | return ret; |
| 156 | 156 | ||
| 157 | /* set the codec system clock for DAC and ADC */ | 157 | /* set the codec system clock for DAC and ADC */ |
| 158 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, | 158 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, |
| 159 | SND_SOC_CLOCK_IN); | 159 | SND_SOC_CLOCK_IN); |
| 160 | if (ret < 0) | 160 | if (ret < 0) |
| 161 | return ret; | 161 | return ret; |
| 162 | 162 | ||
| 163 | /* set the I2S system clock as input (unused) */ | 163 | /* set the I2S system clock as input (unused) */ |
| 164 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 164 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
| 165 | SND_SOC_CLOCK_IN); | 165 | SND_SOC_CLOCK_IN); |
| 166 | if (ret < 0) | 166 | if (ret < 0) |
| 167 | return ret; | 167 | return ret; |
| @@ -247,7 +247,7 @@ SND_SOC_DAPM_HP("Headset Jack", NULL), | |||
| 247 | }; | 247 | }; |
| 248 | 248 | ||
| 249 | /* Corgi machine audio map (connections to the codec pins) */ | 249 | /* Corgi machine audio map (connections to the codec pins) */ |
| 250 | static const char *audio_map[][3] = { | 250 | static const struct snd_soc_dapm_route audio_map[] = { |
| 251 | 251 | ||
| 252 | /* headset Jack - in = micin, out = LHPOUT*/ | 252 | /* headset Jack - in = micin, out = LHPOUT*/ |
| 253 | {"Headset Jack", NULL, "LHPOUT"}, | 253 | {"Headset Jack", NULL, "LHPOUT"}, |
| @@ -265,8 +265,6 @@ static const char *audio_map[][3] = { | |||
| 265 | 265 | ||
| 266 | /* Same as the above but no mic bias for line signals */ | 266 | /* Same as the above but no mic bias for line signals */ |
| 267 | {"MICIN", NULL, "Line Jack"}, | 267 | {"MICIN", NULL, "Line Jack"}, |
| 268 | |||
| 269 | {NULL, NULL, NULL}, | ||
| 270 | }; | 268 | }; |
| 271 | 269 | ||
| 272 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 270 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
| @@ -291,8 +289,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) | |||
| 291 | { | 289 | { |
| 292 | int i, err; | 290 | int i, err; |
| 293 | 291 | ||
| 294 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | 292 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); |
| 295 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | 293 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); |
| 296 | 294 | ||
| 297 | /* Add corgi specific controls */ | 295 | /* Add corgi specific controls */ |
| 298 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { | 296 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { |
| @@ -303,15 +301,13 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) | |||
| 303 | } | 301 | } |
| 304 | 302 | ||
| 305 | /* Add corgi specific widgets */ | 303 | /* Add corgi specific widgets */ |
| 306 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) | 304 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
| 307 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | 305 | ARRAY_SIZE(wm8731_dapm_widgets)); |
| 308 | 306 | ||
| 309 | /* Set up corgi specific audio path audio_map */ | 307 | /* Set up corgi specific audio path audio_map */ |
| 310 | for (i = 0; audio_map[i][0] != NULL; i++) | 308 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 311 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 312 | audio_map[i][1], audio_map[i][2]); | ||
| 313 | 309 | ||
| 314 | snd_soc_dapm_sync_endpoints(codec); | 310 | snd_soc_dapm_sync(codec); |
| 315 | return 0; | 311 | return 0; |
| 316 | } | 312 | } |
| 317 | 313 | ||
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c new file mode 100644 index 000000000000..02dcac39cdf6 --- /dev/null +++ b/sound/soc/pxa/em-x270.c | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | /* | ||
| 2 | * em-x270.c -- SoC audio for EM-X270 | ||
| 3 | * | ||
| 4 | * Copyright 2007 CompuLab, Ltd. | ||
| 5 | * | ||
| 6 | * Author: Mike Rapoport <mike@compulab.co.il> | ||
| 7 | * | ||
| 8 | * Copied from tosa.c: | ||
| 9 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
| 10 | * Copyright 2005 Openedhand Ltd. | ||
| 11 | * | ||
| 12 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
| 13 | * Richard Purdie <richard@openedhand.com> | ||
| 14 | * | ||
| 15 | * This program is free software; you can redistribute it and/or modify it | ||
| 16 | * under the terms of the GNU General Public License as published by the | ||
| 17 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 18 | * option) any later version. | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/moduleparam.h> | ||
| 24 | #include <linux/device.h> | ||
| 25 | |||
| 26 | #include <sound/driver.h> | ||
| 27 | #include <sound/core.h> | ||
| 28 | #include <sound/pcm.h> | ||
| 29 | #include <sound/soc.h> | ||
| 30 | #include <sound/soc-dapm.h> | ||
| 31 | |||
| 32 | #include <asm/mach-types.h> | ||
| 33 | #include <asm/arch/pxa-regs.h> | ||
| 34 | #include <asm/arch/hardware.h> | ||
| 35 | #include <asm/arch/audio.h> | ||
| 36 | |||
| 37 | #include "../codecs/wm9712.h" | ||
| 38 | #include "pxa2xx-pcm.h" | ||
| 39 | #include "pxa2xx-ac97.h" | ||
| 40 | |||
| 41 | static struct snd_soc_dai_link em_x270_dai[] = { | ||
| 42 | { | ||
| 43 | .name = "AC97", | ||
| 44 | .stream_name = "AC97 HiFi", | ||
| 45 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
| 46 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], | ||
| 47 | }, | ||
| 48 | { | ||
| 49 | .name = "AC97 Aux", | ||
| 50 | .stream_name = "AC97 Aux", | ||
| 51 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
| 52 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | ||
| 53 | }, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static struct snd_soc_machine em_x270 = { | ||
| 57 | .name = "EM-X270", | ||
| 58 | .dai_link = em_x270_dai, | ||
| 59 | .num_links = ARRAY_SIZE(em_x270_dai), | ||
| 60 | }; | ||
| 61 | |||
| 62 | static struct snd_soc_device em_x270_snd_devdata = { | ||
| 63 | .machine = &em_x270, | ||
| 64 | .platform = &pxa2xx_soc_platform, | ||
| 65 | .codec_dev = &soc_codec_dev_wm9712, | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct platform_device *em_x270_snd_device; | ||
| 69 | |||
| 70 | static int __init em_x270_init(void) | ||
| 71 | { | ||
| 72 | int ret; | ||
| 73 | |||
| 74 | if (!machine_is_em_x270()) | ||
| 75 | return -ENODEV; | ||
| 76 | |||
| 77 | em_x270_snd_device = platform_device_alloc("soc-audio", -1); | ||
| 78 | if (!em_x270_snd_device) | ||
| 79 | return -ENOMEM; | ||
| 80 | |||
| 81 | platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata); | ||
| 82 | em_x270_snd_devdata.dev = &em_x270_snd_device->dev; | ||
| 83 | ret = platform_device_add(em_x270_snd_device); | ||
| 84 | |||
| 85 | if (ret) | ||
| 86 | platform_device_put(em_x270_snd_device); | ||
| 87 | |||
| 88 | return ret; | ||
| 89 | } | ||
| 90 | |||
| 91 | static void __exit em_x270_exit(void) | ||
| 92 | { | ||
| 93 | platform_device_unregister(em_x270_snd_device); | ||
| 94 | } | ||
| 95 | |||
| 96 | module_init(em_x270_init); | ||
| 97 | module_exit(em_x270_exit); | ||
| 98 | |||
| 99 | /* Module information */ | ||
| 100 | MODULE_AUTHOR("Mike Rapoport"); | ||
| 101 | MODULE_DESCRIPTION("ALSA SoC EM-X270"); | ||
| 102 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 7e830b218943..65a4e9a8c39e 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
| @@ -48,8 +48,6 @@ static int poodle_spk_func; | |||
| 48 | 48 | ||
| 49 | static void poodle_ext_control(struct snd_soc_codec *codec) | 49 | static void poodle_ext_control(struct snd_soc_codec *codec) |
| 50 | { | 50 | { |
| 51 | int spk = 0; | ||
| 52 | |||
| 53 | /* set up jack connection */ | 51 | /* set up jack connection */ |
| 54 | if (poodle_jack_func == POODLE_HP) { | 52 | if (poodle_jack_func == POODLE_HP) { |
| 55 | /* set = unmute headphone */ | 53 | /* set = unmute headphone */ |
| @@ -57,23 +55,23 @@ static void poodle_ext_control(struct snd_soc_codec *codec) | |||
| 57 | POODLE_LOCOMO_GPIO_MUTE_L, 1); | 55 | POODLE_LOCOMO_GPIO_MUTE_L, 1); |
| 58 | locomo_gpio_write(&poodle_locomo_device.dev, | 56 | locomo_gpio_write(&poodle_locomo_device.dev, |
| 59 | POODLE_LOCOMO_GPIO_MUTE_R, 1); | 57 | POODLE_LOCOMO_GPIO_MUTE_R, 1); |
| 60 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | 58 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
| 61 | } else { | 59 | } else { |
| 62 | locomo_gpio_write(&poodle_locomo_device.dev, | 60 | locomo_gpio_write(&poodle_locomo_device.dev, |
| 63 | POODLE_LOCOMO_GPIO_MUTE_L, 0); | 61 | POODLE_LOCOMO_GPIO_MUTE_L, 0); |
| 64 | locomo_gpio_write(&poodle_locomo_device.dev, | 62 | locomo_gpio_write(&poodle_locomo_device.dev, |
| 65 | POODLE_LOCOMO_GPIO_MUTE_R, 0); | 63 | POODLE_LOCOMO_GPIO_MUTE_R, 0); |
| 66 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 64 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
| 67 | } | 65 | } |
| 68 | 66 | ||
| 69 | if (poodle_spk_func == POODLE_SPK_ON) | ||
| 70 | spk = 1; | ||
| 71 | |||
| 72 | /* set the enpoints to their new connetion states */ | 67 | /* set the enpoints to their new connetion states */ |
| 73 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); | 68 | if (poodle_spk_func == POODLE_SPK_ON) |
| 69 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
| 70 | else | ||
| 71 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); | ||
| 74 | 72 | ||
| 75 | /* signal a DAPM event */ | 73 | /* signal a DAPM event */ |
| 76 | snd_soc_dapm_sync_endpoints(codec); | 74 | snd_soc_dapm_sync(codec); |
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | static int poodle_startup(struct snd_pcm_substream *substream) | 77 | static int poodle_startup(struct snd_pcm_substream *substream) |
| @@ -104,8 +102,8 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, | |||
| 104 | struct snd_pcm_hw_params *params) | 102 | struct snd_pcm_hw_params *params) |
| 105 | { | 103 | { |
| 106 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 104 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 107 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 105 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 108 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 106 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 109 | unsigned int clk = 0; | 107 | unsigned int clk = 0; |
| 110 | int ret = 0; | 108 | int ret = 0; |
| 111 | 109 | ||
| @@ -124,25 +122,25 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, | |||
| 124 | } | 122 | } |
| 125 | 123 | ||
| 126 | /* set codec DAI configuration */ | 124 | /* set codec DAI configuration */ |
| 127 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 125 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
| 128 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 126 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 129 | if (ret < 0) | 127 | if (ret < 0) |
| 130 | return ret; | 128 | return ret; |
| 131 | 129 | ||
| 132 | /* set cpu DAI configuration */ | 130 | /* set cpu DAI configuration */ |
| 133 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 131 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
| 134 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 132 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 135 | if (ret < 0) | 133 | if (ret < 0) |
| 136 | return ret; | 134 | return ret; |
| 137 | 135 | ||
| 138 | /* set the codec system clock for DAC and ADC */ | 136 | /* set the codec system clock for DAC and ADC */ |
| 139 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, | 137 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, |
| 140 | SND_SOC_CLOCK_IN); | 138 | SND_SOC_CLOCK_IN); |
| 141 | if (ret < 0) | 139 | if (ret < 0) |
| 142 | return ret; | 140 | return ret; |
| 143 | 141 | ||
| 144 | /* set the I2S system clock as input (unused) */ | 142 | /* set the I2S system clock as input (unused) */ |
| 145 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 143 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
| 146 | SND_SOC_CLOCK_IN); | 144 | SND_SOC_CLOCK_IN); |
| 147 | if (ret < 0) | 145 | if (ret < 0) |
| 148 | return ret; | 146 | return ret; |
| @@ -215,8 +213,8 @@ SND_SOC_DAPM_HP("Headphone Jack", NULL), | |||
| 215 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), | 213 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), |
| 216 | }; | 214 | }; |
| 217 | 215 | ||
| 218 | /* Corgi machine audio_mapnections to the codec pins */ | 216 | /* Corgi machine connections to the codec pins */ |
| 219 | static const char *audio_map[][3] = { | 217 | static const struct snd_soc_dapm_route audio_map[] = { |
| 220 | 218 | ||
| 221 | /* headphone connected to LHPOUT1, RHPOUT1 */ | 219 | /* headphone connected to LHPOUT1, RHPOUT1 */ |
| 222 | {"Headphone Jack", NULL, "LHPOUT"}, | 220 | {"Headphone Jack", NULL, "LHPOUT"}, |
| @@ -225,8 +223,6 @@ static const char *audio_map[][3] = { | |||
| 225 | /* speaker connected to LOUT, ROUT */ | 223 | /* speaker connected to LOUT, ROUT */ |
| 226 | {"Ext Spk", NULL, "ROUT"}, | 224 | {"Ext Spk", NULL, "ROUT"}, |
| 227 | {"Ext Spk", NULL, "LOUT"}, | 225 | {"Ext Spk", NULL, "LOUT"}, |
| 228 | |||
| 229 | {NULL, NULL, NULL}, | ||
| 230 | }; | 226 | }; |
| 231 | 227 | ||
| 232 | static const char *jack_function[] = {"Off", "Headphone"}; | 228 | static const char *jack_function[] = {"Off", "Headphone"}; |
| @@ -250,9 +246,9 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) | |||
| 250 | { | 246 | { |
| 251 | int i, err; | 247 | int i, err; |
| 252 | 248 | ||
| 253 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | 249 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); |
| 254 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | 250 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); |
| 255 | snd_soc_dapm_set_endpoint(codec, "MICIN", 1); | 251 | snd_soc_dapm_enable_pin(codec, "MICIN"); |
| 256 | 252 | ||
| 257 | /* Add poodle specific controls */ | 253 | /* Add poodle specific controls */ |
| 258 | for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { | 254 | for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { |
| @@ -263,15 +259,13 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) | |||
| 263 | } | 259 | } |
| 264 | 260 | ||
| 265 | /* Add poodle specific widgets */ | 261 | /* Add poodle specific widgets */ |
| 266 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) | 262 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
| 267 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | 263 | ARRAY_SIZE(wm8731_dapm_widgets)); |
| 268 | 264 | ||
| 269 | /* Set up poodle specific audio path audio_map */ | 265 | /* Set up poodle specific audio path audio_map */ |
| 270 | for (i = 0; audio_map[i][0] != NULL; i++) | 266 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 271 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 272 | audio_map[i][1], audio_map[i][2]); | ||
| 273 | 267 | ||
| 274 | snd_soc_dapm_sync_endpoints(codec); | 268 | snd_soc_dapm_sync(codec); |
| 275 | return 0; | 269 | return 0; |
| 276 | } | 270 | } |
| 277 | 271 | ||
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 97ec2d90547c..059af815ea0c 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
| @@ -283,7 +283,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { | |||
| 283 | 283 | ||
| 284 | #ifdef CONFIG_PM | 284 | #ifdef CONFIG_PM |
| 285 | static int pxa2xx_ac97_suspend(struct platform_device *pdev, | 285 | static int pxa2xx_ac97_suspend(struct platform_device *pdev, |
| 286 | struct snd_soc_cpu_dai *dai) | 286 | struct snd_soc_dai *dai) |
| 287 | { | 287 | { |
| 288 | GCR |= GCR_ACLINK_OFF; | 288 | GCR |= GCR_ACLINK_OFF; |
| 289 | clk_disable(ac97_clk); | 289 | clk_disable(ac97_clk); |
| @@ -291,7 +291,7 @@ static int pxa2xx_ac97_suspend(struct platform_device *pdev, | |||
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | static int pxa2xx_ac97_resume(struct platform_device *pdev, | 293 | static int pxa2xx_ac97_resume(struct platform_device *pdev, |
| 294 | struct snd_soc_cpu_dai *dai) | 294 | struct snd_soc_dai *dai) |
| 295 | { | 295 | { |
| 296 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | 296 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); |
| 297 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | 297 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); |
| @@ -310,7 +310,8 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev, | |||
| 310 | #define pxa2xx_ac97_resume NULL | 310 | #define pxa2xx_ac97_resume NULL |
| 311 | #endif | 311 | #endif |
| 312 | 312 | ||
| 313 | static int pxa2xx_ac97_probe(struct platform_device *pdev) | 313 | static int pxa2xx_ac97_probe(struct platform_device *pdev, |
| 314 | struct snd_soc_dai *dai) | ||
| 314 | { | 315 | { |
| 315 | int ret; | 316 | int ret; |
| 316 | 317 | ||
| @@ -355,7 +356,8 @@ static int pxa2xx_ac97_probe(struct platform_device *pdev) | |||
| 355 | return ret; | 356 | return ret; |
| 356 | } | 357 | } |
| 357 | 358 | ||
| 358 | static void pxa2xx_ac97_remove(struct platform_device *pdev) | 359 | static void pxa2xx_ac97_remove(struct platform_device *pdev, |
| 360 | struct snd_soc_dai *dai) | ||
| 359 | { | 361 | { |
| 360 | GCR |= GCR_ACLINK_OFF; | 362 | GCR |= GCR_ACLINK_OFF; |
| 361 | free_irq(IRQ_AC97, NULL); | 363 | free_irq(IRQ_AC97, NULL); |
| @@ -372,7 +374,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, | |||
| 372 | struct snd_pcm_hw_params *params) | 374 | struct snd_pcm_hw_params *params) |
| 373 | { | 375 | { |
| 374 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 376 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 375 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 377 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 376 | 378 | ||
| 377 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 379 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 378 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; | 380 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; |
| @@ -386,7 +388,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, | |||
| 386 | struct snd_pcm_hw_params *params) | 388 | struct snd_pcm_hw_params *params) |
| 387 | { | 389 | { |
| 388 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 390 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 389 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 391 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 390 | 392 | ||
| 391 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 393 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 392 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; | 394 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; |
| @@ -400,7 +402,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, | |||
| 400 | struct snd_pcm_hw_params *params) | 402 | struct snd_pcm_hw_params *params) |
| 401 | { | 403 | { |
| 402 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 404 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 403 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 405 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 404 | 406 | ||
| 405 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 407 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 406 | return -ENODEV; | 408 | return -ENODEV; |
| @@ -418,7 +420,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, | |||
| 418 | * There is only 1 physical AC97 interface for pxa2xx, but it | 420 | * There is only 1 physical AC97 interface for pxa2xx, but it |
| 419 | * has extra fifo's that can be used for aux DACs and ADCs. | 421 | * has extra fifo's that can be used for aux DACs and ADCs. |
| 420 | */ | 422 | */ |
| 421 | struct snd_soc_cpu_dai pxa_ac97_dai[] = { | 423 | struct snd_soc_dai pxa_ac97_dai[] = { |
| 422 | { | 424 | { |
| 423 | .name = "pxa2xx-ac97", | 425 | .name = "pxa2xx-ac97", |
| 424 | .id = 0, | 426 | .id = 0, |
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h index b8ccfee095c4..e390de8edcd4 100644 --- a/sound/soc/pxa/pxa2xx-ac97.h +++ b/sound/soc/pxa/pxa2xx-ac97.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | #define PXA2XX_DAI_AC97_AUX 1 | 14 | #define PXA2XX_DAI_AC97_AUX 1 |
| 15 | #define PXA2XX_DAI_AC97_MIC 2 | 15 | #define PXA2XX_DAI_AC97_MIC 2 |
| 16 | 16 | ||
| 17 | extern struct snd_soc_cpu_dai pxa_ac97_dai[3]; | 17 | extern struct snd_soc_dai pxa_ac97_dai[3]; |
| 18 | 18 | ||
| 19 | /* platform data */ | 19 | /* platform data */ |
| 20 | extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; | 20 | extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 425071030970..9c06553b9267 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
| @@ -9,9 +9,6 @@ | |||
| 9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. | 11 | * option) any later version. |
| 12 | * | ||
| 13 | * Revision history | ||
| 14 | * 12th Aug 2005 Initial version. | ||
| 15 | */ | 12 | */ |
| 16 | 13 | ||
| 17 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| @@ -80,7 +77,7 @@ static struct pxa2xx_gpio gpio_bus[] = { | |||
| 80 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) | 77 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) |
| 81 | { | 78 | { |
| 82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 79 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 83 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 80 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 84 | 81 | ||
| 85 | if (!cpu_dai->active) { | 82 | if (!cpu_dai->active) { |
| 86 | SACR0 |= SACR0_RST; | 83 | SACR0 |= SACR0_RST; |
| @@ -101,7 +98,7 @@ static int pxa_i2s_wait(void) | |||
| 101 | return 0; | 98 | return 0; |
| 102 | } | 99 | } |
| 103 | 100 | ||
| 104 | static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 101 | static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
| 105 | unsigned int fmt) | 102 | unsigned int fmt) |
| 106 | { | 103 | { |
| 107 | /* interface format */ | 104 | /* interface format */ |
| @@ -127,7 +124,7 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | |||
| 127 | return 0; | 124 | return 0; |
| 128 | } | 125 | } |
| 129 | 126 | ||
| 130 | static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 127 | static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
| 131 | int clk_id, unsigned int freq, int dir) | 128 | int clk_id, unsigned int freq, int dir) |
| 132 | { | 129 | { |
| 133 | if (clk_id != PXA2XX_I2S_SYSCLK) | 130 | if (clk_id != PXA2XX_I2S_SYSCLK) |
| @@ -143,7 +140,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
| 143 | struct snd_pcm_hw_params *params) | 140 | struct snd_pcm_hw_params *params) |
| 144 | { | 141 | { |
| 145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 142 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 146 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 143 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 147 | 144 | ||
| 148 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); | 145 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); |
| 149 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); | 146 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); |
| @@ -240,7 +237,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) | |||
| 240 | 237 | ||
| 241 | #ifdef CONFIG_PM | 238 | #ifdef CONFIG_PM |
| 242 | static int pxa2xx_i2s_suspend(struct platform_device *dev, | 239 | static int pxa2xx_i2s_suspend(struct platform_device *dev, |
| 243 | struct snd_soc_cpu_dai *dai) | 240 | struct snd_soc_dai *dai) |
| 244 | { | 241 | { |
| 245 | if (!dai->active) | 242 | if (!dai->active) |
| 246 | return 0; | 243 | return 0; |
| @@ -258,7 +255,7 @@ static int pxa2xx_i2s_suspend(struct platform_device *dev, | |||
| 258 | } | 255 | } |
| 259 | 256 | ||
| 260 | static int pxa2xx_i2s_resume(struct platform_device *pdev, | 257 | static int pxa2xx_i2s_resume(struct platform_device *pdev, |
| 261 | struct snd_soc_cpu_dai *dai) | 258 | struct snd_soc_dai *dai) |
| 262 | { | 259 | { |
| 263 | if (!dai->active) | 260 | if (!dai->active) |
| 264 | return 0; | 261 | return 0; |
| @@ -283,7 +280,7 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev, | |||
| 283 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | 280 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ |
| 284 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | 281 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) |
| 285 | 282 | ||
| 286 | struct snd_soc_cpu_dai pxa_i2s_dai = { | 283 | struct snd_soc_dai pxa_i2s_dai = { |
| 287 | .name = "pxa2xx-i2s", | 284 | .name = "pxa2xx-i2s", |
| 288 | .id = 0, | 285 | .id = 0, |
| 289 | .type = SND_SOC_DAI_I2S, | 286 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h index 4435bd9f884f..e2def441153e 100644 --- a/sound/soc/pxa/pxa2xx-i2s.h +++ b/sound/soc/pxa/pxa2xx-i2s.h | |||
| @@ -15,6 +15,6 @@ | |||
| 15 | /* I2S clock */ | 15 | /* I2S clock */ |
| 16 | #define PXA2XX_I2S_SYSCLK 0 | 16 | #define PXA2XX_I2S_SYSCLK 0 |
| 17 | 17 | ||
| 18 | extern struct snd_soc_cpu_dai pxa_i2s_dai; | 18 | extern struct snd_soc_dai pxa_i2s_dai; |
| 19 | 19 | ||
| 20 | #endif | 20 | #endif |
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 01ad7bf716b7..2df03ee5819e 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
| @@ -330,7 +330,7 @@ static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
| 330 | 330 | ||
| 331 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; | 331 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; |
| 332 | 332 | ||
| 333 | int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | 333 | int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
| 334 | struct snd_pcm *pcm) | 334 | struct snd_pcm *pcm) |
| 335 | { | 335 | { |
| 336 | int ret = 0; | 336 | int ret = 0; |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index d8b8372db00e..64385797da5d 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
| @@ -12,9 +12,6 @@ | |||
| 12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
| 13 | * option) any later version. | 13 | * option) any later version. |
| 14 | * | 14 | * |
| 15 | * Revision history | ||
| 16 | * 30th Nov 2005 Initial version. | ||
| 17 | * | ||
| 18 | */ | 15 | */ |
| 19 | 16 | ||
| 20 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| @@ -54,60 +51,60 @@ static int spitz_spk_func; | |||
| 54 | static void spitz_ext_control(struct snd_soc_codec *codec) | 51 | static void spitz_ext_control(struct snd_soc_codec *codec) |
| 55 | { | 52 | { |
| 56 | if (spitz_spk_func == SPITZ_SPK_ON) | 53 | if (spitz_spk_func == SPITZ_SPK_ON) |
| 57 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); | 54 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
| 58 | else | 55 | else |
| 59 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0); | 56 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); |
| 60 | 57 | ||
| 61 | /* set up jack connection */ | 58 | /* set up jack connection */ |
| 62 | switch (spitz_jack_func) { | 59 | switch (spitz_jack_func) { |
| 63 | case SPITZ_HP: | 60 | case SPITZ_HP: |
| 64 | /* enable and unmute hp jack, disable mic bias */ | 61 | /* enable and unmute hp jack, disable mic bias */ |
| 65 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 62 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
| 66 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | 63 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
| 67 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 64 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
| 68 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | 65 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
| 69 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 66 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
| 70 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 67 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
| 71 | break; | 68 | break; |
| 72 | case SPITZ_MIC: | 69 | case SPITZ_MIC: |
| 73 | /* enable mic jack and bias, mute hp */ | 70 | /* enable mic jack and bias, mute hp */ |
| 74 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 71 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
| 75 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 72 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
| 76 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 73 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
| 77 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | 74 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
| 78 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 75 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
| 79 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 76 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
| 80 | break; | 77 | break; |
| 81 | case SPITZ_LINE: | 78 | case SPITZ_LINE: |
| 82 | /* enable line jack, disable mic bias and mute hp */ | 79 | /* enable line jack, disable mic bias and mute hp */ |
| 83 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 80 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
| 84 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 81 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
| 85 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | 82 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
| 86 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 1); | 83 | snd_soc_dapm_enable_pin(codec, "Line Jack"); |
| 87 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 84 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
| 88 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 85 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
| 89 | break; | 86 | break; |
| 90 | case SPITZ_HEADSET: | 87 | case SPITZ_HEADSET: |
| 91 | /* enable and unmute headset jack enable mic bias, mute L hp */ | 88 | /* enable and unmute headset jack enable mic bias, mute L hp */ |
| 92 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 89 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
| 93 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | 90 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
| 94 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 91 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
| 95 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1); | 92 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); |
| 96 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 93 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
| 97 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 94 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
| 98 | break; | 95 | break; |
| 99 | case SPITZ_HP_OFF: | 96 | case SPITZ_HP_OFF: |
| 100 | 97 | ||
| 101 | /* jack removed, everything off */ | 98 | /* jack removed, everything off */ |
| 102 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 99 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
| 103 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 100 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
| 104 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | 101 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
| 105 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 102 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
| 106 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 103 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
| 107 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 104 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
| 108 | break; | 105 | break; |
| 109 | } | 106 | } |
| 110 | snd_soc_dapm_sync_endpoints(codec); | 107 | snd_soc_dapm_sync(codec); |
| 111 | } | 108 | } |
| 112 | 109 | ||
| 113 | static int spitz_startup(struct snd_pcm_substream *substream) | 110 | static int spitz_startup(struct snd_pcm_substream *substream) |
| @@ -124,8 +121,8 @@ static int spitz_hw_params(struct snd_pcm_substream *substream, | |||
| 124 | struct snd_pcm_hw_params *params) | 121 | struct snd_pcm_hw_params *params) |
| 125 | { | 122 | { |
| 126 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 123 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 127 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 124 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 128 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 125 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 129 | unsigned int clk = 0; | 126 | unsigned int clk = 0; |
| 130 | int ret = 0; | 127 | int ret = 0; |
| 131 | 128 | ||
| @@ -144,25 +141,25 @@ static int spitz_hw_params(struct snd_pcm_substream *substream, | |||
| 144 | } | 141 | } |
| 145 | 142 | ||
| 146 | /* set codec DAI configuration */ | 143 | /* set codec DAI configuration */ |
| 147 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 144 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
| 148 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 145 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 149 | if (ret < 0) | 146 | if (ret < 0) |
| 150 | return ret; | 147 | return ret; |
| 151 | 148 | ||
| 152 | /* set cpu DAI configuration */ | 149 | /* set cpu DAI configuration */ |
| 153 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 150 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
| 154 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 151 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 155 | if (ret < 0) | 152 | if (ret < 0) |
| 156 | return ret; | 153 | return ret; |
| 157 | 154 | ||
| 158 | /* set the codec system clock for DAC and ADC */ | 155 | /* set the codec system clock for DAC and ADC */ |
| 159 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk, | 156 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, |
| 160 | SND_SOC_CLOCK_IN); | 157 | SND_SOC_CLOCK_IN); |
| 161 | if (ret < 0) | 158 | if (ret < 0) |
| 162 | return ret; | 159 | return ret; |
| 163 | 160 | ||
| 164 | /* set the I2S system clock as input (unused) */ | 161 | /* set the I2S system clock as input (unused) */ |
| 165 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 162 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
| 166 | SND_SOC_CLOCK_IN); | 163 | SND_SOC_CLOCK_IN); |
| 167 | if (ret < 0) | 164 | if (ret < 0) |
| 168 | return ret; | 165 | return ret; |
| @@ -250,7 +247,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | |||
| 250 | }; | 247 | }; |
| 251 | 248 | ||
| 252 | /* Spitz machine audio_map */ | 249 | /* Spitz machine audio_map */ |
| 253 | static const char *audio_map[][3] = { | 250 | static const struct snd_soc_dapm_route audio_map[] = { |
| 254 | 251 | ||
| 255 | /* headphone connected to LOUT1, ROUT1 */ | 252 | /* headphone connected to LOUT1, ROUT1 */ |
| 256 | {"Headphone Jack", NULL, "LOUT1"}, | 253 | {"Headphone Jack", NULL, "LOUT1"}, |
| @@ -269,8 +266,6 @@ static const char *audio_map[][3] = { | |||
| 269 | 266 | ||
| 270 | /* line is connected to input 1 - no bias */ | 267 | /* line is connected to input 1 - no bias */ |
| 271 | {"LINPUT1", NULL, "Line Jack"}, | 268 | {"LINPUT1", NULL, "Line Jack"}, |
| 272 | |||
| 273 | {NULL, NULL, NULL}, | ||
| 274 | }; | 269 | }; |
| 275 | 270 | ||
| 276 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 271 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
| @@ -296,13 +291,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) | |||
| 296 | int i, err; | 291 | int i, err; |
| 297 | 292 | ||
| 298 | /* NC codec pins */ | 293 | /* NC codec pins */ |
| 299 | snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0); | 294 | snd_soc_dapm_disable_pin(codec, "RINPUT1"); |
| 300 | snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0); | 295 | snd_soc_dapm_disable_pin(codec, "LINPUT2"); |
| 301 | snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0); | 296 | snd_soc_dapm_disable_pin(codec, "RINPUT2"); |
| 302 | snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0); | 297 | snd_soc_dapm_disable_pin(codec, "LINPUT3"); |
| 303 | snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0); | 298 | snd_soc_dapm_disable_pin(codec, "RINPUT3"); |
| 304 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | 299 | snd_soc_dapm_disable_pin(codec, "OUT3"); |
| 305 | snd_soc_dapm_set_endpoint(codec, "MONO", 0); | 300 | snd_soc_dapm_disable_pin(codec, "MONO"); |
| 306 | 301 | ||
| 307 | /* Add spitz specific controls */ | 302 | /* Add spitz specific controls */ |
| 308 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { | 303 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { |
| @@ -313,15 +308,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) | |||
| 313 | } | 308 | } |
| 314 | 309 | ||
| 315 | /* Add spitz specific widgets */ | 310 | /* Add spitz specific widgets */ |
| 316 | for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) | 311 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
| 317 | snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); | 312 | ARRAY_SIZE(wm8750_dapm_widgets)); |
| 318 | 313 | ||
| 319 | /* Set up spitz specific audio path audio_map */ | 314 | /* Set up spitz specific audio paths */ |
| 320 | for (i = 0; audio_map[i][0] != NULL; i++) | 315 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 321 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 322 | audio_map[i][1], audio_map[i][2]); | ||
| 323 | 316 | ||
| 324 | snd_soc_dapm_sync_endpoints(codec); | 317 | snd_soc_dapm_sync(codec); |
| 325 | return 0; | 318 | return 0; |
| 326 | } | 319 | } |
| 327 | 320 | ||
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 7346d7e5d066..b6edb61a3a30 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
| @@ -12,9 +12,6 @@ | |||
| 12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
| 13 | * option) any later version. | 13 | * option) any later version. |
| 14 | * | 14 | * |
| 15 | * Revision history | ||
| 16 | * 30th Nov 2005 Initial version. | ||
| 17 | * | ||
| 18 | * GPIO's | 15 | * GPIO's |
| 19 | * 1 - Jack Insertion | 16 | * 1 - Jack Insertion |
| 20 | * 5 - Hookswitch (headset answer/hang up switch) | 17 | * 5 - Hookswitch (headset answer/hang up switch) |
| @@ -55,29 +52,31 @@ static int tosa_spk_func; | |||
| 55 | 52 | ||
| 56 | static void tosa_ext_control(struct snd_soc_codec *codec) | 53 | static void tosa_ext_control(struct snd_soc_codec *codec) |
| 57 | { | 54 | { |
| 58 | int spk = 0, mic_int = 0, hp = 0, hs = 0; | ||
| 59 | |||
| 60 | /* set up jack connection */ | 55 | /* set up jack connection */ |
| 61 | switch (tosa_jack_func) { | 56 | switch (tosa_jack_func) { |
| 62 | case TOSA_HP: | 57 | case TOSA_HP: |
| 63 | hp = 1; | 58 | snd_soc_dapm_disable_pin(codec, "Mic (Internal)"); |
| 59 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
| 60 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
| 64 | break; | 61 | break; |
| 65 | case TOSA_MIC_INT: | 62 | case TOSA_MIC_INT: |
| 66 | mic_int = 1; | 63 | snd_soc_dapm_enable_pin(codec, "Mic (Internal)"); |
| 64 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
| 65 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
| 67 | break; | 66 | break; |
| 68 | case TOSA_HEADSET: | 67 | case TOSA_HEADSET: |
| 69 | hs = 1; | 68 | snd_soc_dapm_disable_pin(codec, "Mic (Internal)"); |
| 69 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
| 70 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); | ||
| 70 | break; | 71 | break; |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | if (tosa_spk_func == TOSA_SPK_ON) | 74 | if (tosa_spk_func == TOSA_SPK_ON) |
| 74 | spk = 1; | 75 | snd_soc_dapm_enable_pin(codec, "Speaker"); |
| 76 | else | ||
| 77 | snd_soc_dapm_disable_pin(codec, "Speaker"); | ||
| 75 | 78 | ||
| 76 | snd_soc_dapm_set_endpoint(codec, "Speaker", spk); | 79 | snd_soc_dapm_sync(codec); |
| 77 | snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int); | ||
| 78 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); | ||
| 79 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); | ||
| 80 | snd_soc_dapm_sync_endpoints(codec); | ||
| 81 | } | 80 | } |
| 82 | 81 | ||
| 83 | static int tosa_startup(struct snd_pcm_substream *substream) | 82 | static int tosa_startup(struct snd_pcm_substream *substream) |
| @@ -154,7 +153,7 @@ SND_SOC_DAPM_SPK("Speaker", NULL), | |||
| 154 | }; | 153 | }; |
| 155 | 154 | ||
| 156 | /* tosa audio map */ | 155 | /* tosa audio map */ |
| 157 | static const char *audio_map[][3] = { | 156 | static const struct snd_soc_dapm_route audio_map[] = { |
| 158 | 157 | ||
| 159 | /* headphone connected to HPOUTL, HPOUTR */ | 158 | /* headphone connected to HPOUTL, HPOUTR */ |
| 160 | {"Headphone Jack", NULL, "HPOUTL"}, | 159 | {"Headphone Jack", NULL, "HPOUTL"}, |
| @@ -173,8 +172,6 @@ static const char *audio_map[][3] = { | |||
| 173 | {"Headset Jack", NULL, "HPOUTR"}, | 172 | {"Headset Jack", NULL, "HPOUTR"}, |
| 174 | {"LINEINR", NULL, "Mic Bias"}, | 173 | {"LINEINR", NULL, "Mic Bias"}, |
| 175 | {"Mic Bias", NULL, "Headset Jack"}, | 174 | {"Mic Bias", NULL, "Headset Jack"}, |
| 176 | |||
| 177 | {NULL, NULL, NULL}, | ||
| 178 | }; | 175 | }; |
| 179 | 176 | ||
| 180 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 177 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
| @@ -196,8 +193,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec) | |||
| 196 | { | 193 | { |
| 197 | int i, err; | 194 | int i, err; |
| 198 | 195 | ||
| 199 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | 196 | snd_soc_dapm_disable_pin(codec, "OUT3"); |
| 200 | snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0); | 197 | snd_soc_dapm_disable_pin(codec, "MONOOUT"); |
| 201 | 198 | ||
| 202 | /* add tosa specific controls */ | 199 | /* add tosa specific controls */ |
| 203 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { | 200 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { |
| @@ -208,17 +205,13 @@ static int tosa_ac97_init(struct snd_soc_codec *codec) | |||
| 208 | } | 205 | } |
| 209 | 206 | ||
| 210 | /* add tosa specific widgets */ | 207 | /* add tosa specific widgets */ |
| 211 | for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) { | 208 | snd_soc_dapm_new_controls(codec, tosa_dapm_widgets, |
| 212 | snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]); | 209 | ARRAY_SIZE(tosa_dapm_widgets)); |
| 213 | } | ||
| 214 | 210 | ||
| 215 | /* set up tosa specific audio path audio_map */ | 211 | /* set up tosa specific audio path audio_map */ |
| 216 | for (i = 0; audio_map[i][0] != NULL; i++) { | 212 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
| 217 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
| 218 | audio_map[i][1], audio_map[i][2]); | ||
| 219 | } | ||
| 220 | 213 | ||
| 221 | snd_soc_dapm_sync_endpoints(codec); | 214 | snd_soc_dapm_sync(codec); |
| 222 | return 0; | 215 | return 0; |
| 223 | } | 216 | } |
| 224 | 217 | ||
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 1f6dbfc4caa8..b9f2353effeb 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | config SND_S3C24XX_SOC | 1 | config SND_S3C24XX_SOC |
| 2 | tristate "SoC Audio for the Samsung S3C24XX chips" | 2 | tristate "SoC Audio for the Samsung S3C24XX chips" |
| 3 | depends on ARCH_S3C2410 && SND_SOC | 3 | depends on ARCH_S3C2410 |
| 4 | select SND_PCM | ||
| 5 | help | 4 | help |
| 6 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
| 7 | the S3C24XX AC97, I2S or SSP interface. You will also need | 6 | the S3C24XX AC97, I2S or SSP interface. You will also need |
| @@ -16,7 +15,6 @@ config SND_S3C2412_SOC_I2S | |||
| 16 | config SND_S3C2443_SOC_AC97 | 15 | config SND_S3C2443_SOC_AC97 |
| 17 | tristate | 16 | tristate |
| 18 | select AC97_BUS | 17 | select AC97_BUS |
| 19 | select SND_AC97_CODEC | ||
| 20 | select SND_SOC_AC97_BUS | 18 | select SND_SOC_AC97_BUS |
| 21 | 19 | ||
| 22 | config SND_S3C24XX_SOC_NEO1973_WM8753 | 20 | config SND_S3C24XX_SOC_NEO1973_WM8753 |
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 0e9d1c5f2484..4d7a9aa15f1a 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
| @@ -10,10 +10,6 @@ | |||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. | 11 | * option) any later version. |
| 12 | * | 12 | * |
| 13 | * Revision history | ||
| 14 | * 20th Jan 2007 Initial version. | ||
| 15 | * 05th Feb 2007 Rename all to Neo1973 | ||
| 16 | * | ||
| 17 | */ | 13 | */ |
| 18 | 14 | ||
| 19 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| @@ -26,6 +22,7 @@ | |||
| 26 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
| 27 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
| 28 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
| 25 | #include <sound/tlv.h> | ||
| 29 | 26 | ||
| 30 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
| 31 | #include <asm/hardware/scoop.h> | 28 | #include <asm/hardware/scoop.h> |
| @@ -43,6 +40,14 @@ | |||
| 43 | #include "s3c24xx-pcm.h" | 40 | #include "s3c24xx-pcm.h" |
| 44 | #include "s3c24xx-i2s.h" | 41 | #include "s3c24xx-i2s.h" |
| 45 | 42 | ||
| 43 | /* Debugging stuff */ | ||
| 44 | #define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0 | ||
| 45 | #if S3C24XX_SOC_NEO1973_WM8753_DEBUG | ||
| 46 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x) | ||
| 47 | #else | ||
| 48 | #define DBG(x...) | ||
| 49 | #endif | ||
| 50 | |||
| 46 | /* define the scenarios */ | 51 | /* define the scenarios */ |
| 47 | #define NEO_AUDIO_OFF 0 | 52 | #define NEO_AUDIO_OFF 0 |
| 48 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 | 53 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 |
| @@ -61,12 +66,14 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
| 61 | struct snd_pcm_hw_params *params) | 66 | struct snd_pcm_hw_params *params) |
| 62 | { | 67 | { |
| 63 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 68 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 64 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 69 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 65 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 70 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 66 | unsigned int pll_out = 0, bclk = 0; | 71 | unsigned int pll_out = 0, bclk = 0; |
| 67 | int ret = 0; | 72 | int ret = 0; |
| 68 | unsigned long iis_clkrate; | 73 | unsigned long iis_clkrate; |
| 69 | 74 | ||
| 75 | DBG("Entered %s\n", __func__); | ||
| 76 | |||
| 70 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 77 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
| 71 | 78 | ||
| 72 | switch (params_rate(params)) { | 79 | switch (params_rate(params)) { |
| @@ -101,44 +108,44 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
| 101 | } | 108 | } |
| 102 | 109 | ||
| 103 | /* set codec DAI configuration */ | 110 | /* set codec DAI configuration */ |
| 104 | ret = codec_dai->dai_ops.set_fmt(codec_dai, | 111 | ret = snd_soc_dai_set_fmt(codec_dai, |
| 105 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 112 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
| 106 | SND_SOC_DAIFMT_CBM_CFM); | 113 | SND_SOC_DAIFMT_CBM_CFM); |
| 107 | if (ret < 0) | 114 | if (ret < 0) |
| 108 | return ret; | 115 | return ret; |
| 109 | 116 | ||
| 110 | /* set cpu DAI configuration */ | 117 | /* set cpu DAI configuration */ |
| 111 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, | 118 | ret = snd_soc_dai_set_fmt(cpu_dai, |
| 112 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 119 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
| 113 | SND_SOC_DAIFMT_CBM_CFM); | 120 | SND_SOC_DAIFMT_CBM_CFM); |
| 114 | if (ret < 0) | 121 | if (ret < 0) |
| 115 | return ret; | 122 | return ret; |
| 116 | 123 | ||
| 117 | /* set the codec system clock for DAC and ADC */ | 124 | /* set the codec system clock for DAC and ADC */ |
| 118 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out, | 125 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, |
| 119 | SND_SOC_CLOCK_IN); | 126 | SND_SOC_CLOCK_IN); |
| 120 | if (ret < 0) | 127 | if (ret < 0) |
| 121 | return ret; | 128 | return ret; |
| 122 | 129 | ||
| 123 | /* set MCLK division for sample rate */ | 130 | /* set MCLK division for sample rate */ |
| 124 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | 131 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, |
| 125 | S3C2410_IISMOD_32FS); | 132 | S3C2410_IISMOD_32FS); |
| 126 | if (ret < 0) | 133 | if (ret < 0) |
| 127 | return ret; | 134 | return ret; |
| 128 | 135 | ||
| 129 | /* set codec BCLK division for sample rate */ | 136 | /* set codec BCLK division for sample rate */ |
| 130 | ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); | 137 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); |
| 131 | if (ret < 0) | 138 | if (ret < 0) |
| 132 | return ret; | 139 | return ret; |
| 133 | 140 | ||
| 134 | /* set prescaler division for sample rate */ | 141 | /* set prescaler division for sample rate */ |
| 135 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | 142 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, |
| 136 | S3C24XX_PRESCALE(4, 4)); | 143 | S3C24XX_PRESCALE(4, 4)); |
| 137 | if (ret < 0) | 144 | if (ret < 0) |
| 138 | return ret; | 145 | return ret; |
| 139 | 146 | ||
| 140 | /* codec PLL input is PCLK/4 */ | 147 | /* codec PLL input is PCLK/4 */ |
| 141 | ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, | 148 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, |
| 142 | iis_clkrate / 4, pll_out); | 149 | iis_clkrate / 4, pll_out); |
| 143 | if (ret < 0) | 150 | if (ret < 0) |
| 144 | return ret; | 151 | return ret; |
| @@ -149,10 +156,12 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
| 149 | static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | 156 | static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) |
| 150 | { | 157 | { |
| 151 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 158 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 152 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 159 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 160 | |||
| 161 | DBG("Entered %s\n", __func__); | ||
| 153 | 162 | ||
| 154 | /* disable the PLL */ | 163 | /* disable the PLL */ |
| 155 | return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0); | 164 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); |
| 156 | } | 165 | } |
| 157 | 166 | ||
| 158 | /* | 167 | /* |
| @@ -167,11 +176,13 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
| 167 | struct snd_pcm_hw_params *params) | 176 | struct snd_pcm_hw_params *params) |
| 168 | { | 177 | { |
| 169 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 178 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 170 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 179 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 171 | unsigned int pcmdiv = 0; | 180 | unsigned int pcmdiv = 0; |
| 172 | int ret = 0; | 181 | int ret = 0; |
| 173 | unsigned long iis_clkrate; | 182 | unsigned long iis_clkrate; |
| 174 | 183 | ||
| 184 | DBG("Entered %s\n", __func__); | ||
| 185 | |||
| 175 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 186 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
| 176 | 187 | ||
| 177 | if (params_rate(params) != 8000) | 188 | if (params_rate(params) != 8000) |
| @@ -183,24 +194,24 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
| 183 | 194 | ||
| 184 | /* todo: gg check mode (DSP_B) against CSR datasheet */ | 195 | /* todo: gg check mode (DSP_B) against CSR datasheet */ |
| 185 | /* set codec DAI configuration */ | 196 | /* set codec DAI configuration */ |
| 186 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | | 197 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | |
| 187 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 198 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
| 188 | if (ret < 0) | 199 | if (ret < 0) |
| 189 | return ret; | 200 | return ret; |
| 190 | 201 | ||
| 191 | /* set the codec system clock for DAC and ADC */ | 202 | /* set the codec system clock for DAC and ADC */ |
| 192 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, | 203 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, |
| 193 | SND_SOC_CLOCK_IN); | 204 | SND_SOC_CLOCK_IN); |
| 194 | if (ret < 0) | 205 | if (ret < 0) |
| 195 | return ret; | 206 | return ret; |
| 196 | 207 | ||
| 197 | /* set codec PCM division for sample rate */ | 208 | /* set codec PCM division for sample rate */ |
| 198 | ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); | 209 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); |
| 199 | if (ret < 0) | 210 | if (ret < 0) |
| 200 | return ret; | 211 | return ret; |
| 201 | 212 | ||
| 202 | /* configue and enable PLL for 12.288MHz output */ | 213 | /* configue and enable PLL for 12.288MHz output */ |
| 203 | ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, | 214 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, |
| 204 | iis_clkrate / 4, 12288000); | 215 | iis_clkrate / 4, 12288000); |
| 205 | if (ret < 0) | 216 | if (ret < 0) |
| 206 | return ret; | 217 | return ret; |
| @@ -211,10 +222,12 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
| 211 | static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | 222 | static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) |
| 212 | { | 223 | { |
| 213 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 224 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 214 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 225 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
| 226 | |||
| 227 | DBG("Entered %s\n", __func__); | ||
| 215 | 228 | ||
| 216 | /* disable the PLL */ | 229 | /* disable the PLL */ |
| 217 | return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0); | 230 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); |
| 218 | } | 231 | } |
| 219 | 232 | ||
| 220 | static struct snd_soc_ops neo1973_voice_ops = { | 233 | static struct snd_soc_ops neo1973_voice_ops = { |
| @@ -233,79 +246,81 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, | |||
| 233 | 246 | ||
| 234 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) | 247 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) |
| 235 | { | 248 | { |
| 249 | DBG("Entered %s\n", __func__); | ||
| 250 | |||
| 236 | switch (neo1973_scenario) { | 251 | switch (neo1973_scenario) { |
| 237 | case NEO_AUDIO_OFF: | 252 | case NEO_AUDIO_OFF: |
| 238 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 253 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
| 239 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 254 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
| 240 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 255 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
| 241 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 256 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 242 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 257 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 243 | break; | 258 | break; |
| 244 | case NEO_GSM_CALL_AUDIO_HANDSET: | 259 | case NEO_GSM_CALL_AUDIO_HANDSET: |
| 245 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 260 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
| 246 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); | 261 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); |
| 247 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); | 262 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); |
| 248 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 263 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 249 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); | 264 | snd_soc_dapm_enable_pin(codec, "Call Mic"); |
| 250 | break; | 265 | break; |
| 251 | case NEO_GSM_CALL_AUDIO_HEADSET: | 266 | case NEO_GSM_CALL_AUDIO_HEADSET: |
| 252 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 267 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
| 253 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); | 268 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); |
| 254 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); | 269 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); |
| 255 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); | 270 | snd_soc_dapm_enable_pin(codec, "Headset Mic"); |
| 256 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 271 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 257 | break; | 272 | break; |
| 258 | case NEO_GSM_CALL_AUDIO_BLUETOOTH: | 273 | case NEO_GSM_CALL_AUDIO_BLUETOOTH: |
| 259 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 274 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
| 260 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); | 275 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); |
| 261 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); | 276 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); |
| 262 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 277 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 263 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 278 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 264 | break; | 279 | break; |
| 265 | case NEO_STEREO_TO_SPEAKERS: | 280 | case NEO_STEREO_TO_SPEAKERS: |
| 266 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 281 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
| 267 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 282 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
| 268 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 283 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
| 269 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 284 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 270 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 285 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 271 | break; | 286 | break; |
| 272 | case NEO_STEREO_TO_HEADPHONES: | 287 | case NEO_STEREO_TO_HEADPHONES: |
| 273 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 288 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
| 274 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 289 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
| 275 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 290 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
| 276 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 291 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 277 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 292 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 278 | break; | 293 | break; |
| 279 | case NEO_CAPTURE_HANDSET: | 294 | case NEO_CAPTURE_HANDSET: |
| 280 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 295 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
| 281 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 296 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
| 282 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 297 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
| 283 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 298 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 284 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); | 299 | snd_soc_dapm_enable_pin(codec, "Call Mic"); |
| 285 | break; | 300 | break; |
| 286 | case NEO_CAPTURE_HEADSET: | 301 | case NEO_CAPTURE_HEADSET: |
| 287 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 302 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
| 288 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 303 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
| 289 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 304 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
| 290 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); | 305 | snd_soc_dapm_enable_pin(codec, "Headset Mic"); |
| 291 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 306 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 292 | break; | 307 | break; |
| 293 | case NEO_CAPTURE_BLUETOOTH: | 308 | case NEO_CAPTURE_BLUETOOTH: |
| 294 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 309 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
| 295 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 310 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
| 296 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 311 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
| 297 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 312 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 298 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 313 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 299 | break; | 314 | break; |
| 300 | default: | 315 | default: |
| 301 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 316 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
| 302 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 317 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
| 303 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 318 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
| 304 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 319 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
| 305 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 320 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
| 306 | } | 321 | } |
| 307 | 322 | ||
| 308 | snd_soc_dapm_sync_endpoints(codec); | 323 | snd_soc_dapm_sync(codec); |
| 309 | 324 | ||
| 310 | return 0; | 325 | return 0; |
| 311 | } | 326 | } |
| @@ -315,6 +330,8 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, | |||
| 315 | { | 330 | { |
| 316 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 331 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 317 | 332 | ||
| 333 | DBG("Entered %s\n", __func__); | ||
| 334 | |||
| 318 | if (neo1973_scenario == ucontrol->value.integer.value[0]) | 335 | if (neo1973_scenario == ucontrol->value.integer.value[0]) |
| 319 | return 0; | 336 | return 0; |
| 320 | 337 | ||
| @@ -327,6 +344,8 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; | |||
| 327 | 344 | ||
| 328 | static void lm4857_write_regs(void) | 345 | static void lm4857_write_regs(void) |
| 329 | { | 346 | { |
| 347 | DBG("Entered %s\n", __func__); | ||
| 348 | |||
| 330 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) | 349 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) |
| 331 | printk(KERN_ERR "lm4857: i2c write failed\n"); | 350 | printk(KERN_ERR "lm4857: i2c write failed\n"); |
| 332 | } | 351 | } |
| @@ -338,6 +357,8 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol, | |||
| 338 | int shift = (kcontrol->private_value >> 8) & 0x0F; | 357 | int shift = (kcontrol->private_value >> 8) & 0x0F; |
| 339 | int mask = (kcontrol->private_value >> 16) & 0xFF; | 358 | int mask = (kcontrol->private_value >> 16) & 0xFF; |
| 340 | 359 | ||
| 360 | DBG("Entered %s\n", __func__); | ||
| 361 | |||
| 341 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; | 362 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; |
| 342 | return 0; | 363 | return 0; |
| 343 | } | 364 | } |
| @@ -364,6 +385,8 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | |||
| 364 | { | 385 | { |
| 365 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; | 386 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; |
| 366 | 387 | ||
| 388 | DBG("Entered %s\n", __func__); | ||
| 389 | |||
| 367 | if (value) | 390 | if (value) |
| 368 | value -= 5; | 391 | value -= 5; |
| 369 | 392 | ||
| @@ -376,6 +399,8 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | |||
| 376 | { | 399 | { |
| 377 | u8 value = ucontrol->value.integer.value[0]; | 400 | u8 value = ucontrol->value.integer.value[0]; |
| 378 | 401 | ||
| 402 | DBG("Entered %s\n", __func__); | ||
| 403 | |||
| 379 | if (value) | 404 | if (value) |
| 380 | value += 5; | 405 | value += 5; |
| 381 | 406 | ||
| @@ -397,8 +422,7 @@ static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | |||
| 397 | }; | 422 | }; |
| 398 | 423 | ||
| 399 | 424 | ||
| 400 | /* example machine audio_mapnections */ | 425 | static const struct snd_soc_dapm_route dapm_routes[] = { |
| 401 | static const char *audio_map[][3] = { | ||
| 402 | 426 | ||
| 403 | /* Connections to the lm4857 amp */ | 427 | /* Connections to the lm4857 amp */ |
| 404 | {"Audio Out", NULL, "LOUT1"}, | 428 | {"Audio Out", NULL, "LOUT1"}, |
| @@ -421,8 +445,6 @@ static const char *audio_map[][3] = { | |||
| 421 | 445 | ||
| 422 | /* Connect the ALC pins */ | 446 | /* Connect the ALC pins */ |
| 423 | {"ACIN", NULL, "ACOP"}, | 447 | {"ACIN", NULL, "ACOP"}, |
| 424 | |||
| 425 | {NULL, NULL, NULL}, | ||
| 426 | }; | 448 | }; |
| 427 | 449 | ||
| 428 | static const char *lm4857_mode[] = { | 450 | static const char *lm4857_mode[] = { |
| @@ -453,13 +475,16 @@ static const struct soc_enum neo_scenario_enum[] = { | |||
| 453 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios), | 475 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios), |
| 454 | }; | 476 | }; |
| 455 | 477 | ||
| 478 | static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); | ||
| 479 | static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); | ||
| 480 | |||
| 456 | static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { | 481 | static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { |
| 457 | SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, | 482 | SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, |
| 458 | lm4857_get_reg, lm4857_set_reg), | 483 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), |
| 459 | SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, | 484 | SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, |
| 460 | lm4857_get_reg, lm4857_set_reg), | 485 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), |
| 461 | SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, | 486 | SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, |
| 462 | lm4857_get_reg, lm4857_set_reg), | 487 | lm4857_get_reg, lm4857_set_reg, mono_tlv), |
| 463 | SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], | 488 | SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], |
| 464 | lm4857_get_mode, lm4857_set_mode), | 489 | lm4857_get_mode, lm4857_set_mode), |
| 465 | SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0], | 490 | SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0], |
| @@ -483,21 +508,23 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) | |||
| 483 | { | 508 | { |
| 484 | int i, err; | 509 | int i, err; |
| 485 | 510 | ||
| 511 | DBG("Entered %s\n", __func__); | ||
| 512 | |||
| 486 | /* set up NC codec pins */ | 513 | /* set up NC codec pins */ |
| 487 | snd_soc_dapm_set_endpoint(codec, "LOUT2", 0); | 514 | snd_soc_dapm_disable_pin(codec, "LOUT2"); |
| 488 | snd_soc_dapm_set_endpoint(codec, "ROUT2", 0); | 515 | snd_soc_dapm_disable_pin(codec, "ROUT2"); |
| 489 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | 516 | snd_soc_dapm_disable_pin(codec, "OUT3"); |
| 490 | snd_soc_dapm_set_endpoint(codec, "OUT4", 0); | 517 | snd_soc_dapm_disable_pin(codec, "OUT4"); |
| 491 | snd_soc_dapm_set_endpoint(codec, "LINE1", 0); | 518 | snd_soc_dapm_disable_pin(codec, "LINE1"); |
| 492 | snd_soc_dapm_set_endpoint(codec, "LINE2", 0); | 519 | snd_soc_dapm_disable_pin(codec, "LINE2"); |
| 493 | 520 | ||
| 494 | 521 | ||
| 495 | /* set endpoints to default mode */ | 522 | /* set endpoints to default mode */ |
| 496 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); | 523 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); |
| 497 | 524 | ||
| 498 | /* Add neo1973 specific widgets */ | 525 | /* Add neo1973 specific widgets */ |
| 499 | for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++) | 526 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, |
| 500 | snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]); | 527 | ARRAY_SIZE(wm8753_dapm_widgets)); |
| 501 | 528 | ||
| 502 | /* add neo1973 specific controls */ | 529 | /* add neo1973 specific controls */ |
| 503 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { | 530 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { |
| @@ -508,20 +535,18 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) | |||
| 508 | return err; | 535 | return err; |
| 509 | } | 536 | } |
| 510 | 537 | ||
| 511 | /* set up neo1973 specific audio path audio_mapnects */ | 538 | /* set up neo1973 specific audio routes */ |
| 512 | for (i = 0; audio_map[i][0] != NULL; i++) { | 539 | err = snd_soc_dapm_add_routes(codec, dapm_routes, |
| 513 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | 540 | ARRAY_SIZE(dapm_routes)); |
| 514 | audio_map[i][1], audio_map[i][2]); | ||
| 515 | } | ||
| 516 | 541 | ||
| 517 | snd_soc_dapm_sync_endpoints(codec); | 542 | snd_soc_dapm_sync(codec); |
| 518 | return 0; | 543 | return 0; |
| 519 | } | 544 | } |
| 520 | 545 | ||
| 521 | /* | 546 | /* |
| 522 | * BT Codec DAI | 547 | * BT Codec DAI |
| 523 | */ | 548 | */ |
| 524 | static struct snd_soc_cpu_dai bt_dai = { | 549 | static struct snd_soc_dai bt_dai = { |
| 525 | .name = "Bluetooth", | 550 | .name = "Bluetooth", |
| 526 | .id = 0, | 551 | .id = 0, |
| 527 | .type = SND_SOC_DAI_PCM, | 552 | .type = SND_SOC_DAI_PCM, |
| @@ -583,6 +608,8 @@ static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind) | |||
| 583 | { | 608 | { |
| 584 | int ret; | 609 | int ret; |
| 585 | 610 | ||
| 611 | DBG("Entered %s\n", __func__); | ||
| 612 | |||
| 586 | client_template.adapter = adap; | 613 | client_template.adapter = adap; |
| 587 | client_template.addr = addr; | 614 | client_template.addr = addr; |
| 588 | 615 | ||
| @@ -606,6 +633,8 @@ exit_err: | |||
| 606 | 633 | ||
| 607 | static int lm4857_i2c_detach(struct i2c_client *client) | 634 | static int lm4857_i2c_detach(struct i2c_client *client) |
| 608 | { | 635 | { |
| 636 | DBG("Entered %s\n", __func__); | ||
| 637 | |||
| 609 | i2c_detach_client(client); | 638 | i2c_detach_client(client); |
| 610 | kfree(client); | 639 | kfree(client); |
| 611 | return 0; | 640 | return 0; |
| @@ -613,6 +642,8 @@ static int lm4857_i2c_detach(struct i2c_client *client) | |||
| 613 | 642 | ||
| 614 | static int lm4857_i2c_attach(struct i2c_adapter *adap) | 643 | static int lm4857_i2c_attach(struct i2c_adapter *adap) |
| 615 | { | 644 | { |
| 645 | DBG("Entered %s\n", __func__); | ||
| 646 | |||
| 616 | return i2c_probe(adap, &addr_data, lm4857_amp_probe); | 647 | return i2c_probe(adap, &addr_data, lm4857_amp_probe); |
| 617 | } | 648 | } |
| 618 | 649 | ||
| @@ -620,6 +651,8 @@ static u8 lm4857_state; | |||
| 620 | 651 | ||
| 621 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | 652 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) |
| 622 | { | 653 | { |
| 654 | DBG("Entered %s\n", __func__); | ||
| 655 | |||
| 623 | dev_dbg(&dev->dev, "lm4857_suspend\n"); | 656 | dev_dbg(&dev->dev, "lm4857_suspend\n"); |
| 624 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; | 657 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; |
| 625 | if (lm4857_state) { | 658 | if (lm4857_state) { |
| @@ -631,6 +664,8 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | |||
| 631 | 664 | ||
| 632 | static int lm4857_resume(struct i2c_client *dev) | 665 | static int lm4857_resume(struct i2c_client *dev) |
| 633 | { | 666 | { |
| 667 | DBG("Entered %s\n", __func__); | ||
| 668 | |||
| 634 | if (lm4857_state) { | 669 | if (lm4857_state) { |
| 635 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); | 670 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); |
| 636 | lm4857_write_regs(); | 671 | lm4857_write_regs(); |
| @@ -640,6 +675,8 @@ static int lm4857_resume(struct i2c_client *dev) | |||
| 640 | 675 | ||
| 641 | static void lm4857_shutdown(struct i2c_client *dev) | 676 | static void lm4857_shutdown(struct i2c_client *dev) |
| 642 | { | 677 | { |
| 678 | DBG("Entered %s\n", __func__); | ||
| 679 | |||
| 643 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); | 680 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); |
| 644 | lm4857_regs[LM4857_CTRL] &= 0xf0; | 681 | lm4857_regs[LM4857_CTRL] &= 0xf0; |
| 645 | lm4857_write_regs(); | 682 | lm4857_write_regs(); |
| @@ -671,6 +708,8 @@ static int __init neo1973_init(void) | |||
| 671 | { | 708 | { |
| 672 | int ret; | 709 | int ret; |
| 673 | 710 | ||
| 711 | DBG("Entered %s\n", __func__); | ||
| 712 | |||
| 674 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); | 713 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); |
| 675 | if (!neo1973_snd_device) | 714 | if (!neo1973_snd_device) |
| 676 | return -ENOMEM; | 715 | return -ENOMEM; |
| @@ -691,6 +730,8 @@ static int __init neo1973_init(void) | |||
| 691 | 730 | ||
| 692 | static void __exit neo1973_exit(void) | 731 | static void __exit neo1973_exit(void) |
| 693 | { | 732 | { |
| 733 | DBG("Entered %s\n", __func__); | ||
| 734 | |||
| 694 | i2c_del_driver(&lm4857_i2c_driver); | 735 | i2c_del_driver(&lm4857_i2c_driver); |
| 695 | platform_device_unregister(neo1973_snd_device); | 736 | platform_device_unregister(neo1973_snd_device); |
| 696 | } | 737 | } |
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index c4a46dd589b3..ee4676ed1283 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c | |||
| @@ -295,7 +295,7 @@ static inline int s3c2412_snd_is_clkmaster(void) | |||
| 295 | /* | 295 | /* |
| 296 | * Set S3C2412 I2S DAI format | 296 | * Set S3C2412 I2S DAI format |
| 297 | */ | 297 | */ |
| 298 | static int s3c2412_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, | 298 | static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
| 299 | unsigned int fmt) | 299 | unsigned int fmt) |
| 300 | { | 300 | { |
| 301 | u32 iismod; | 301 | u32 iismod; |
| @@ -500,7 +500,7 @@ EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); | |||
| 500 | /* | 500 | /* |
| 501 | * Set S3C2412 Clock source | 501 | * Set S3C2412 Clock source |
| 502 | */ | 502 | */ |
| 503 | static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 503 | static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, |
| 504 | int clk_id, unsigned int freq, int dir) | 504 | int clk_id, unsigned int freq, int dir) |
| 505 | { | 505 | { |
| 506 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | 506 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); |
| @@ -528,7 +528,7 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
| 528 | /* | 528 | /* |
| 529 | * Set S3C2412 Clock dividers | 529 | * Set S3C2412 Clock dividers |
| 530 | */ | 530 | */ |
| 531 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 531 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, |
| 532 | int div_id, int div) | 532 | int div_id, int div) |
| 533 | { | 533 | { |
| 534 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | 534 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; |
| @@ -601,7 +601,8 @@ struct clk *s3c2412_get_iisclk(void) | |||
| 601 | EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); | 601 | EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); |
| 602 | 602 | ||
| 603 | 603 | ||
| 604 | static int s3c2412_i2s_probe(struct platform_device *pdev) | 604 | static int s3c2412_i2s_probe(struct platform_device *pdev, |
| 605 | struct snd_soc_dai *dai) | ||
| 605 | { | 606 | { |
| 606 | DBG("Entered %s\n", __func__); | 607 | DBG("Entered %s\n", __func__); |
| 607 | 608 | ||
| @@ -647,7 +648,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev) | |||
| 647 | 648 | ||
| 648 | #ifdef CONFIG_PM | 649 | #ifdef CONFIG_PM |
| 649 | static int s3c2412_i2s_suspend(struct platform_device *dev, | 650 | static int s3c2412_i2s_suspend(struct platform_device *dev, |
| 650 | struct snd_soc_cpu_dai *dai) | 651 | struct snd_soc_dai *dai) |
| 651 | { | 652 | { |
| 652 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | 653 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; |
| 653 | u32 iismod; | 654 | u32 iismod; |
| @@ -675,7 +676,7 @@ static int s3c2412_i2s_suspend(struct platform_device *dev, | |||
| 675 | } | 676 | } |
| 676 | 677 | ||
| 677 | static int s3c2412_i2s_resume(struct platform_device *pdev, | 678 | static int s3c2412_i2s_resume(struct platform_device *pdev, |
| 678 | struct snd_soc_cpu_dai *dai) | 679 | struct snd_soc_dai *dai) |
| 679 | { | 680 | { |
| 680 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | 681 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; |
| 681 | 682 | ||
| @@ -707,7 +708,7 @@ static int s3c2412_i2s_resume(struct platform_device *pdev, | |||
| 707 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 708 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
| 708 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 709 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
| 709 | 710 | ||
| 710 | struct snd_soc_cpu_dai s3c2412_i2s_dai = { | 711 | struct snd_soc_dai s3c2412_i2s_dai = { |
| 711 | .name = "s3c2412-i2s", | 712 | .name = "s3c2412-i2s", |
| 712 | .id = 0, | 713 | .id = 0, |
| 713 | .type = SND_SOC_DAI_I2S, | 714 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h index 27f48e1ffa86..aac08a25e541 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.h +++ b/sound/soc/s3c24xx/s3c2412-i2s.h | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | extern struct clk *s3c2412_get_iisclk(void); | 25 | extern struct clk *s3c2412_get_iisclk(void); |
| 26 | 26 | ||
| 27 | extern struct snd_soc_cpu_dai s3c2412_i2s_dai; | 27 | extern struct snd_soc_dai s3c2412_i2s_dai; |
| 28 | 28 | ||
| 29 | struct s3c2412_rate_calc { | 29 | struct s3c2412_rate_calc { |
| 30 | unsigned int clk_div; /* for prescaler */ | 30 | unsigned int clk_div; /* for prescaler */ |
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index e81d9a6c83da..783349b7fede 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c | |||
| @@ -10,9 +10,6 @@ | |||
| 10 | * This program is free software; you can redistribute it and/or modify | 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 | 11 | * it under the terms of the GNU General Public License version 2 as |
| 12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
| 13 | * | ||
| 14 | * Revision history | ||
| 15 | * 21st Mar 2007 Initial Version | ||
| 16 | */ | 13 | */ |
| 17 | 14 | ||
| 18 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| @@ -212,7 +209,8 @@ static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = { | |||
| 212 | .dma_size = 4, | 209 | .dma_size = 4, |
| 213 | }; | 210 | }; |
| 214 | 211 | ||
| 215 | static int s3c2443_ac97_probe(struct platform_device *pdev) | 212 | static int s3c2443_ac97_probe(struct platform_device *pdev, |
| 213 | struct snd_soc_dai *dai) | ||
| 216 | { | 214 | { |
| 217 | int ret; | 215 | int ret; |
| 218 | u32 ac_glbctrl; | 216 | u32 ac_glbctrl; |
| @@ -263,7 +261,8 @@ static int s3c2443_ac97_probe(struct platform_device *pdev) | |||
| 263 | return ret; | 261 | return ret; |
| 264 | } | 262 | } |
| 265 | 263 | ||
| 266 | static void s3c2443_ac97_remove(struct platform_device *pdev) | 264 | static void s3c2443_ac97_remove(struct platform_device *pdev, |
| 265 | struct snd_soc_dai *dai) | ||
| 267 | { | 266 | { |
| 268 | free_irq(IRQ_S3C244x_AC97, NULL); | 267 | free_irq(IRQ_S3C244x_AC97, NULL); |
| 269 | clk_disable(s3c24xx_ac97.ac97_clk); | 268 | clk_disable(s3c24xx_ac97.ac97_clk); |
| @@ -275,7 +274,7 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, | |||
| 275 | struct snd_pcm_hw_params *params) | 274 | struct snd_pcm_hw_params *params) |
| 276 | { | 275 | { |
| 277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 276 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 278 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 277 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 279 | 278 | ||
| 280 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 279 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 281 | cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out; | 280 | cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out; |
| @@ -317,7 +316,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, | |||
| 317 | struct snd_pcm_hw_params *params) | 316 | struct snd_pcm_hw_params *params) |
| 318 | { | 317 | { |
| 319 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 318 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 320 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 319 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| 321 | 320 | ||
| 322 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 321 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 323 | return -ENODEV; | 322 | return -ENODEV; |
| @@ -353,7 +352,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
| 353 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | 352 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ |
| 354 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 353 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
| 355 | 354 | ||
| 356 | struct snd_soc_cpu_dai s3c2443_ac97_dai[] = { | 355 | struct snd_soc_dai s3c2443_ac97_dai[] = { |
| 357 | { | 356 | { |
| 358 | .name = "s3c2443-ac97", | 357 | .name = "s3c2443-ac97", |
| 359 | .id = 0, | 358 | .id = 0, |
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h index bf03e8ed16c3..a96dcadf28b4 100644 --- a/sound/soc/s3c24xx/s3c24xx-ac97.h +++ b/sound/soc/s3c24xx/s3c24xx-ac97.h | |||
| @@ -26,6 +26,6 @@ | |||
| 26 | #define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97 | 26 | #define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97 |
| 27 | #endif | 27 | #endif |
| 28 | 28 | ||
| 29 | extern struct snd_soc_cpu_dai s3c2443_ac97_dai[]; | 29 | extern struct snd_soc_dai s3c2443_ac97_dai[]; |
| 30 | 30 | ||
| 31 | #endif /*S3C24XXAC97_H_*/ | 31 | #endif /*S3C24XXAC97_H_*/ |
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 1ed6afd45459..397524282b57 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c | |||
| @@ -12,11 +12,6 @@ | |||
| 12 | * under the terms of the GNU General Public License as published by the | 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 | 13 | * Free Software Foundation; either version 2 of the License, or (at your |
| 14 | * option) any later version. | 14 | * option) any later version. |
| 15 | * | ||
| 16 | * | ||
| 17 | * Revision history | ||
| 18 | * 11th Dec 2006 Merged with Simtec driver | ||
| 19 | * 10th Nov 2006 Initial version. | ||
| 20 | */ | 15 | */ |
| 21 | 16 | ||
| 22 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| @@ -180,7 +175,7 @@ static void s3c24xx_snd_rxctrl(int on) | |||
| 180 | static int s3c24xx_snd_lrsync(void) | 175 | static int s3c24xx_snd_lrsync(void) |
| 181 | { | 176 | { |
| 182 | u32 iiscon; | 177 | u32 iiscon; |
| 183 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | 178 | int timeout = 50; /* 5ms */ |
| 184 | 179 | ||
| 185 | DBG("Entered %s\n", __func__); | 180 | DBG("Entered %s\n", __func__); |
| 186 | 181 | ||
| @@ -189,8 +184,9 @@ static int s3c24xx_snd_lrsync(void) | |||
| 189 | if (iiscon & S3C2410_IISCON_LRINDEX) | 184 | if (iiscon & S3C2410_IISCON_LRINDEX) |
| 190 | break; | 185 | break; |
| 191 | 186 | ||
| 192 | if (time_after(jiffies, timeout)) | 187 | if (!timeout--) |
| 193 | return -ETIMEDOUT; | 188 | return -ETIMEDOUT; |
| 189 | udelay(100); | ||
| 194 | } | 190 | } |
| 195 | 191 | ||
| 196 | return 0; | 192 | return 0; |
| @@ -209,7 +205,7 @@ static inline int s3c24xx_snd_is_clkmaster(void) | |||
| 209 | /* | 205 | /* |
| 210 | * Set S3C24xx I2S DAI format | 206 | * Set S3C24xx I2S DAI format |
| 211 | */ | 207 | */ |
| 212 | static int s3c24xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, | 208 | static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
| 213 | unsigned int fmt) | 209 | unsigned int fmt) |
| 214 | { | 210 | { |
| 215 | u32 iismod; | 211 | u32 iismod; |
| @@ -317,7 +313,7 @@ exit_err: | |||
| 317 | /* | 313 | /* |
| 318 | * Set S3C24xx Clock source | 314 | * Set S3C24xx Clock source |
| 319 | */ | 315 | */ |
| 320 | static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 316 | static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, |
| 321 | int clk_id, unsigned int freq, int dir) | 317 | int clk_id, unsigned int freq, int dir) |
| 322 | { | 318 | { |
| 323 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 319 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
| @@ -343,7 +339,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
| 343 | /* | 339 | /* |
| 344 | * Set S3C24xx Clock dividers | 340 | * Set S3C24xx Clock dividers |
| 345 | */ | 341 | */ |
| 346 | static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 342 | static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, |
| 347 | int div_id, int div) | 343 | int div_id, int div) |
| 348 | { | 344 | { |
| 349 | u32 reg; | 345 | u32 reg; |
| @@ -381,7 +377,8 @@ u32 s3c24xx_i2s_get_clockrate(void) | |||
| 381 | } | 377 | } |
| 382 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); | 378 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); |
| 383 | 379 | ||
| 384 | static int s3c24xx_i2s_probe(struct platform_device *pdev) | 380 | static int s3c24xx_i2s_probe(struct platform_device *pdev, |
| 381 | struct snd_soc_dai *dai) | ||
| 385 | { | 382 | { |
| 386 | DBG("Entered %s\n", __func__); | 383 | DBG("Entered %s\n", __func__); |
| 387 | 384 | ||
| @@ -414,7 +411,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) | |||
| 414 | 411 | ||
| 415 | #ifdef CONFIG_PM | 412 | #ifdef CONFIG_PM |
| 416 | static int s3c24xx_i2s_suspend(struct platform_device *pdev, | 413 | static int s3c24xx_i2s_suspend(struct platform_device *pdev, |
| 417 | struct snd_soc_cpu_dai *cpu_dai) | 414 | struct snd_soc_dai *cpu_dai) |
| 418 | { | 415 | { |
| 419 | DBG("Entered %s\n", __func__); | 416 | DBG("Entered %s\n", __func__); |
| 420 | 417 | ||
| @@ -429,7 +426,7 @@ static int s3c24xx_i2s_suspend(struct platform_device *pdev, | |||
| 429 | } | 426 | } |
| 430 | 427 | ||
| 431 | static int s3c24xx_i2s_resume(struct platform_device *pdev, | 428 | static int s3c24xx_i2s_resume(struct platform_device *pdev, |
| 432 | struct snd_soc_cpu_dai *cpu_dai) | 429 | struct snd_soc_dai *cpu_dai) |
| 433 | { | 430 | { |
| 434 | DBG("Entered %s\n", __func__); | 431 | DBG("Entered %s\n", __func__); |
| 435 | clk_enable(s3c24xx_i2s.iis_clk); | 432 | clk_enable(s3c24xx_i2s.iis_clk); |
| @@ -452,7 +449,7 @@ static int s3c24xx_i2s_resume(struct platform_device *pdev, | |||
| 452 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 449 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
| 453 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 450 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
| 454 | 451 | ||
| 455 | struct snd_soc_cpu_dai s3c24xx_i2s_dai = { | 452 | struct snd_soc_dai s3c24xx_i2s_dai = { |
| 456 | .name = "s3c24xx-i2s", | 453 | .name = "s3c24xx-i2s", |
| 457 | .id = 0, | 454 | .id = 0, |
| 458 | .type = SND_SOC_DAI_I2S, | 455 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/s3c24xx/s3c24xx-i2s.h index 537b4ecce8a3..726d91cf4e1c 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.h +++ b/sound/soc/s3c24xx/s3c24xx-i2s.h | |||
| @@ -32,6 +32,6 @@ | |||
| 32 | 32 | ||
| 33 | u32 s3c24xx_i2s_get_clockrate(void); | 33 | u32 s3c24xx_i2s_get_clockrate(void); |
| 34 | 34 | ||
| 35 | extern struct snd_soc_cpu_dai s3c24xx_i2s_dai; | 35 | extern struct snd_soc_dai s3c24xx_i2s_dai; |
| 36 | 36 | ||
| 37 | #endif /*S3C24XXI2S_H_*/ | 37 | #endif /*S3C24XXI2S_H_*/ |
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 7806ae614617..cef79b34dc6f 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c | |||
| @@ -12,10 +12,6 @@ | |||
| 12 | * under the terms of the GNU General Public License as published by the | 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 | 13 | * Free Software Foundation; either version 2 of the License, or (at your |
| 14 | * option) any later version. | 14 | * option) any later version. |
| 15 | * | ||
| 16 | * Revision history | ||
| 17 | * 11th Dec 2006 Merged with Simtec driver | ||
| 18 | * 10th Nov 2006 Initial version. | ||
| 19 | */ | 15 | */ |
| 20 | 16 | ||
| 21 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| @@ -433,7 +429,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
| 433 | static u64 s3c24xx_pcm_dmamask = DMA_32BIT_MASK; | 429 | static u64 s3c24xx_pcm_dmamask = DMA_32BIT_MASK; |
| 434 | 430 | ||
| 435 | static int s3c24xx_pcm_new(struct snd_card *card, | 431 | static int s3c24xx_pcm_new(struct snd_card *card, |
| 436 | struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) | 432 | struct snd_soc_dai *dai, struct snd_pcm *pcm) |
| 437 | { | 433 | { |
| 438 | int ret = 0; | 434 | int ret = 0; |
| 439 | 435 | ||
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index b4a56302b9ab..8515d6ff03f2 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c | |||
| @@ -10,9 +10,6 @@ | |||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. | 11 | * option) any later version. |
| 12 | * | 12 | * |
| 13 | * Revision history | ||
| 14 | * 8th Mar 2007 Initial version. | ||
| 15 | * | ||
| 16 | */ | 13 | */ |
| 17 | 14 | ||
| 18 | #include <linux/module.h> | 15 | #include <linux/module.h> |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 4c1e013381c9..54bd604012af 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
| @@ -3,7 +3,7 @@ menu "SoC Audio support for SuperH" | |||
| 3 | 3 | ||
| 4 | config SND_SOC_PCM_SH7760 | 4 | config SND_SOC_PCM_SH7760 |
| 5 | tristate "SoC Audio support for Renesas SH7760" | 5 | tristate "SoC Audio support for Renesas SH7760" |
| 6 | depends on CPU_SUBTYPE_SH7760 && SND_SOC && SH_DMABRG | 6 | depends on CPU_SUBTYPE_SH7760 && SH_DMABRG |
| 7 | help | 7 | help |
| 8 | Enable this option for SH7760 AC97/I2S audio support. | 8 | Enable this option for SH7760 AC97/I2S audio support. |
| 9 | 9 | ||
| @@ -13,10 +13,9 @@ config SND_SOC_PCM_SH7760 | |||
| 13 | ## | 13 | ## |
| 14 | 14 | ||
| 15 | config SND_SOC_SH4_HAC | 15 | config SND_SOC_SH4_HAC |
| 16 | tristate | ||
| 16 | select AC97_BUS | 17 | select AC97_BUS |
| 17 | select SND_SOC_AC97_BUS | 18 | select SND_SOC_AC97_BUS |
| 18 | select SND_AC97_CODEC | ||
| 19 | tristate | ||
| 20 | 19 | ||
| 21 | config SND_SOC_SH4_SSI | 20 | config SND_SOC_SH4_SSI |
| 22 | tristate | 21 | tristate |
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 7a3ce80d6727..9faa12622d09 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c | |||
| @@ -326,7 +326,7 @@ static void camelot_pcm_free(struct snd_pcm *pcm) | |||
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | static int camelot_pcm_new(struct snd_card *card, | 328 | static int camelot_pcm_new(struct snd_card *card, |
| 329 | struct snd_soc_codec_dai *dai, | 329 | struct snd_soc_dai *dai, |
| 330 | struct snd_pcm *pcm) | 330 | struct snd_pcm *pcm) |
| 331 | { | 331 | { |
| 332 | /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel | 332 | /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel |
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index b7b676b3d671..df7bc345c320 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c | |||
| @@ -266,7 +266,7 @@ static int hac_hw_params(struct snd_pcm_substream *substream, | |||
| 266 | #define AC97_FMTS \ | 266 | #define AC97_FMTS \ |
| 267 | SNDRV_PCM_FMTBIT_S16_LE | 267 | SNDRV_PCM_FMTBIT_S16_LE |
| 268 | 268 | ||
| 269 | struct snd_soc_cpu_dai sh4_hac_dai[] = { | 269 | struct snd_soc_dai sh4_hac_dai[] = { |
| 270 | { | 270 | { |
| 271 | .name = "HAC0", | 271 | .name = "HAC0", |
| 272 | .id = 0, | 272 | .id = 0, |
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index 2f91de84c5c7..92bfaf4774a7 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c | |||
| @@ -20,12 +20,12 @@ | |||
| 20 | #define IPSEL 0xFE400034 | 20 | #define IPSEL 0xFE400034 |
| 21 | 21 | ||
| 22 | /* platform specific structs can be declared here */ | 22 | /* platform specific structs can be declared here */ |
| 23 | extern struct snd_soc_cpu_dai sh4_hac_dai[2]; | 23 | extern struct snd_soc_dai sh4_hac_dai[2]; |
| 24 | extern struct snd_soc_platform sh7760_soc_platform; | 24 | extern struct snd_soc_platform sh7760_soc_platform; |
| 25 | 25 | ||
| 26 | static int machine_init(struct snd_soc_codec *codec) | 26 | static int machine_init(struct snd_soc_codec *codec) |
| 27 | { | 27 | { |
| 28 | snd_soc_dapm_sync_endpoints(codec); | 28 | snd_soc_dapm_sync(codec); |
| 29 | return 0; | 29 | return 0; |
| 30 | } | 30 | } |
| 31 | 31 | ||
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 3388bc3d62d1..55c3464163ab 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c | |||
| @@ -208,7 +208,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream, | |||
| 208 | return 0; | 208 | return 0; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, | 211 | static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, |
| 212 | unsigned int freq, int dir) | 212 | unsigned int freq, int dir) |
| 213 | { | 213 | { |
| 214 | struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; | 214 | struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; |
| @@ -222,7 +222,7 @@ static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, | |||
| 222 | * This divider is used to generate the SSI_SCK (I2S bitclock) from the | 222 | * This divider is used to generate the SSI_SCK (I2S bitclock) from the |
| 223 | * clock at the HAC_BIT_CLK ("oversampling clock") pin. | 223 | * clock at the HAC_BIT_CLK ("oversampling clock") pin. |
| 224 | */ | 224 | */ |
| 225 | static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div) | 225 | static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div) |
| 226 | { | 226 | { |
| 227 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; | 227 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; |
| 228 | unsigned long ssicr; | 228 | unsigned long ssicr; |
| @@ -245,7 +245,7 @@ static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div) | |||
| 245 | return 0; | 245 | return 0; |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt) | 248 | static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
| 249 | { | 249 | { |
| 250 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; | 250 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; |
| 251 | unsigned long ssicr = SSIREG(SSICR); | 251 | unsigned long ssicr = SSIREG(SSICR); |
| @@ -332,7 +332,7 @@ static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt) | |||
| 332 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ | 332 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ |
| 333 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) | 333 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) |
| 334 | 334 | ||
| 335 | struct snd_soc_cpu_dai sh4_ssi_dai[] = { | 335 | struct snd_soc_dai sh4_ssi_dai[] = { |
| 336 | { | 336 | { |
| 337 | .name = "SSI0", | 337 | .name = "SSI0", |
| 338 | .id = 0, | 338 | .id = 0, |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e148db940cfc..83f1190293a8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
| @@ -14,10 +14,6 @@ | |||
| 14 | * Free Software Foundation; either version 2 of the License, or (at your | 14 | * Free Software Foundation; either version 2 of the License, or (at your |
| 15 | * option) any later version. | 15 | * option) any later version. |
| 16 | * | 16 | * |
| 17 | * Revision history | ||
| 18 | * 12th Aug 2005 Initial version. | ||
| 19 | * 25th Oct 2005 Working Codec, Interface and Platform registration. | ||
| 20 | * | ||
| 21 | * TODO: | 17 | * TODO: |
| 22 | * o Add hw rules to enforce rates, etc. | 18 | * o Add hw rules to enforce rates, etc. |
| 23 | * o More testing with other codecs/machines. | 19 | * o More testing with other codecs/machines. |
| @@ -112,9 +108,9 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) | |||
| 112 | } | 108 | } |
| 113 | #endif | 109 | #endif |
| 114 | 110 | ||
| 115 | static inline const char* get_dai_name(int type) | 111 | static inline const char *get_dai_name(int type) |
| 116 | { | 112 | { |
| 117 | switch(type) { | 113 | switch (type) { |
| 118 | case SND_SOC_DAI_AC97_BUS: | 114 | case SND_SOC_DAI_AC97_BUS: |
| 119 | case SND_SOC_DAI_AC97: | 115 | case SND_SOC_DAI_AC97: |
| 120 | return "AC97"; | 116 | return "AC97"; |
| @@ -138,8 +134,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
| 138 | struct snd_pcm_runtime *runtime = substream->runtime; | 134 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 139 | struct snd_soc_dai_link *machine = rtd->dai; | 135 | struct snd_soc_dai_link *machine = rtd->dai; |
| 140 | struct snd_soc_platform *platform = socdev->platform; | 136 | struct snd_soc_platform *platform = socdev->platform; |
| 141 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 137 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
| 142 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 138 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
| 143 | int ret = 0; | 139 | int ret = 0; |
| 144 | 140 | ||
| 145 | mutex_lock(&pcm_mutex); | 141 | mutex_lock(&pcm_mutex); |
| @@ -182,9 +178,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
| 182 | /* Check that the codec and cpu DAI's are compatible */ | 178 | /* Check that the codec and cpu DAI's are compatible */ |
| 183 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 179 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 184 | runtime->hw.rate_min = | 180 | runtime->hw.rate_min = |
| 185 | max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min); | 181 | max(codec_dai->playback.rate_min, |
| 182 | cpu_dai->playback.rate_min); | ||
| 186 | runtime->hw.rate_max = | 183 | runtime->hw.rate_max = |
| 187 | min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max); | 184 | min(codec_dai->playback.rate_max, |
| 185 | cpu_dai->playback.rate_max); | ||
| 188 | runtime->hw.channels_min = | 186 | runtime->hw.channels_min = |
| 189 | max(codec_dai->playback.channels_min, | 187 | max(codec_dai->playback.channels_min, |
| 190 | cpu_dai->playback.channels_min); | 188 | cpu_dai->playback.channels_min); |
| @@ -197,9 +195,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
| 197 | codec_dai->playback.rates & cpu_dai->playback.rates; | 195 | codec_dai->playback.rates & cpu_dai->playback.rates; |
| 198 | } else { | 196 | } else { |
| 199 | runtime->hw.rate_min = | 197 | runtime->hw.rate_min = |
| 200 | max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min); | 198 | max(codec_dai->capture.rate_min, |
| 199 | cpu_dai->capture.rate_min); | ||
| 201 | runtime->hw.rate_max = | 200 | runtime->hw.rate_max = |
| 202 | min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max); | 201 | min(codec_dai->capture.rate_max, |
| 202 | cpu_dai->capture.rate_max); | ||
| 203 | runtime->hw.channels_min = | 203 | runtime->hw.channels_min = |
| 204 | max(codec_dai->capture.channels_min, | 204 | max(codec_dai->capture.channels_min, |
| 205 | cpu_dai->capture.channels_min); | 205 | cpu_dai->capture.channels_min); |
| @@ -229,7 +229,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
| 229 | goto machine_err; | 229 | goto machine_err; |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name); | 232 | dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); |
| 233 | dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); | 233 | dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); |
| 234 | dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | 234 | dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, |
| 235 | runtime->hw.channels_max); | 235 | runtime->hw.channels_max); |
| @@ -272,11 +272,11 @@ static void close_delayed_work(struct work_struct *work) | |||
| 272 | struct snd_soc_device *socdev = | 272 | struct snd_soc_device *socdev = |
| 273 | container_of(work, struct snd_soc_device, delayed_work.work); | 273 | container_of(work, struct snd_soc_device, delayed_work.work); |
| 274 | struct snd_soc_codec *codec = socdev->codec; | 274 | struct snd_soc_codec *codec = socdev->codec; |
| 275 | struct snd_soc_codec_dai *codec_dai; | 275 | struct snd_soc_dai *codec_dai; |
| 276 | int i; | 276 | int i; |
| 277 | 277 | ||
| 278 | mutex_lock(&pcm_mutex); | 278 | mutex_lock(&pcm_mutex); |
| 279 | for(i = 0; i < codec->num_dai; i++) { | 279 | for (i = 0; i < codec->num_dai; i++) { |
| 280 | codec_dai = &codec->dai[i]; | 280 | codec_dai = &codec->dai[i]; |
| 281 | 281 | ||
| 282 | dbg("pop wq checking: %s status: %s waiting: %s\n", | 282 | dbg("pop wq checking: %s status: %s waiting: %s\n", |
| @@ -287,12 +287,12 @@ static void close_delayed_work(struct work_struct *work) | |||
| 287 | /* are we waiting on this codec DAI stream */ | 287 | /* are we waiting on this codec DAI stream */ |
| 288 | if (codec_dai->pop_wait == 1) { | 288 | if (codec_dai->pop_wait == 1) { |
| 289 | 289 | ||
| 290 | /* power down the codec to D1 if no longer active */ | 290 | /* Reduce power if no longer active */ |
| 291 | if (codec->active == 0) { | 291 | if (codec->active == 0) { |
| 292 | dbg("pop wq D1 %s %s\n", codec->name, | 292 | dbg("pop wq D1 %s %s\n", codec->name, |
| 293 | codec_dai->playback.stream_name); | 293 | codec_dai->playback.stream_name); |
| 294 | snd_soc_dapm_device_event(socdev, | 294 | snd_soc_dapm_set_bias_level(socdev, |
| 295 | SNDRV_CTL_POWER_D1); | 295 | SND_SOC_BIAS_PREPARE); |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | codec_dai->pop_wait = 0; | 298 | codec_dai->pop_wait = 0; |
| @@ -300,12 +300,12 @@ static void close_delayed_work(struct work_struct *work) | |||
| 300 | codec_dai->playback.stream_name, | 300 | codec_dai->playback.stream_name, |
| 301 | SND_SOC_DAPM_STREAM_STOP); | 301 | SND_SOC_DAPM_STREAM_STOP); |
| 302 | 302 | ||
| 303 | /* power down the codec power domain if no longer active */ | 303 | /* Fall into standby if no longer active */ |
| 304 | if (codec->active == 0) { | 304 | if (codec->active == 0) { |
| 305 | dbg("pop wq D3 %s %s\n", codec->name, | 305 | dbg("pop wq D3 %s %s\n", codec->name, |
| 306 | codec_dai->playback.stream_name); | 306 | codec_dai->playback.stream_name); |
| 307 | snd_soc_dapm_device_event(socdev, | 307 | snd_soc_dapm_set_bias_level(socdev, |
| 308 | SNDRV_CTL_POWER_D3hot); | 308 | SND_SOC_BIAS_STANDBY); |
| 309 | } | 309 | } |
| 310 | } | 310 | } |
| 311 | } | 311 | } |
| @@ -323,8 +323,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
| 323 | struct snd_soc_device *socdev = rtd->socdev; | 323 | struct snd_soc_device *socdev = rtd->socdev; |
| 324 | struct snd_soc_dai_link *machine = rtd->dai; | 324 | struct snd_soc_dai_link *machine = rtd->dai; |
| 325 | struct snd_soc_platform *platform = socdev->platform; | 325 | struct snd_soc_platform *platform = socdev->platform; |
| 326 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 326 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
| 327 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 327 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
| 328 | struct snd_soc_codec *codec = socdev->codec; | 328 | struct snd_soc_codec *codec = socdev->codec; |
| 329 | 329 | ||
| 330 | mutex_lock(&pcm_mutex); | 330 | mutex_lock(&pcm_mutex); |
| @@ -365,8 +365,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
| 365 | SND_SOC_DAPM_STREAM_STOP); | 365 | SND_SOC_DAPM_STREAM_STOP); |
| 366 | 366 | ||
| 367 | if (codec->active == 0 && codec_dai->pop_wait == 0) | 367 | if (codec->active == 0 && codec_dai->pop_wait == 0) |
| 368 | snd_soc_dapm_device_event(socdev, | 368 | snd_soc_dapm_set_bias_level(socdev, |
| 369 | SNDRV_CTL_POWER_D3hot); | 369 | SND_SOC_BIAS_STANDBY); |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | mutex_unlock(&pcm_mutex); | 372 | mutex_unlock(&pcm_mutex); |
| @@ -384,8 +384,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 384 | struct snd_soc_device *socdev = rtd->socdev; | 384 | struct snd_soc_device *socdev = rtd->socdev; |
| 385 | struct snd_soc_dai_link *machine = rtd->dai; | 385 | struct snd_soc_dai_link *machine = rtd->dai; |
| 386 | struct snd_soc_platform *platform = socdev->platform; | 386 | struct snd_soc_platform *platform = socdev->platform; |
| 387 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 387 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
| 388 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 388 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
| 389 | struct snd_soc_codec *codec = socdev->codec; | 389 | struct snd_soc_codec *codec = socdev->codec; |
| 390 | int ret = 0; | 390 | int ret = 0; |
| 391 | 391 | ||
| @@ -434,14 +434,14 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 434 | else { | 434 | else { |
| 435 | codec_dai->pop_wait = 0; | 435 | codec_dai->pop_wait = 0; |
| 436 | cancel_delayed_work(&socdev->delayed_work); | 436 | cancel_delayed_work(&socdev->delayed_work); |
| 437 | if (codec_dai->dai_ops.digital_mute) | 437 | snd_soc_dai_digital_mute(codec_dai, 0); |
| 438 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | ||
| 439 | } | 438 | } |
| 440 | } else { | 439 | } else { |
| 441 | /* no delayed work - do we need to power up codec */ | 440 | /* no delayed work - do we need to power up codec */ |
| 442 | if (codec->dapm_state != SNDRV_CTL_POWER_D0) { | 441 | if (codec->bias_level != SND_SOC_BIAS_ON) { |
| 443 | 442 | ||
| 444 | snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D1); | 443 | snd_soc_dapm_set_bias_level(socdev, |
| 444 | SND_SOC_BIAS_PREPARE); | ||
| 445 | 445 | ||
| 446 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 446 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 447 | snd_soc_dapm_stream_event(codec, | 447 | snd_soc_dapm_stream_event(codec, |
| @@ -452,9 +452,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 452 | codec_dai->capture.stream_name, | 452 | codec_dai->capture.stream_name, |
| 453 | SND_SOC_DAPM_STREAM_START); | 453 | SND_SOC_DAPM_STREAM_START); |
| 454 | 454 | ||
| 455 | snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D0); | 455 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); |
| 456 | if (codec_dai->dai_ops.digital_mute) | 456 | snd_soc_dai_digital_mute(codec_dai, 0); |
| 457 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | ||
| 458 | 457 | ||
| 459 | } else { | 458 | } else { |
| 460 | /* codec already powered - power on widgets */ | 459 | /* codec already powered - power on widgets */ |
| @@ -466,8 +465,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 466 | snd_soc_dapm_stream_event(codec, | 465 | snd_soc_dapm_stream_event(codec, |
| 467 | codec_dai->capture.stream_name, | 466 | codec_dai->capture.stream_name, |
| 468 | SND_SOC_DAPM_STREAM_START); | 467 | SND_SOC_DAPM_STREAM_START); |
| 469 | if (codec_dai->dai_ops.digital_mute) | 468 | |
| 470 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | 469 | snd_soc_dai_digital_mute(codec_dai, 0); |
| 471 | } | 470 | } |
| 472 | } | 471 | } |
| 473 | 472 | ||
| @@ -488,8 +487,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 488 | struct snd_soc_device *socdev = rtd->socdev; | 487 | struct snd_soc_device *socdev = rtd->socdev; |
| 489 | struct snd_soc_dai_link *machine = rtd->dai; | 488 | struct snd_soc_dai_link *machine = rtd->dai; |
| 490 | struct snd_soc_platform *platform = socdev->platform; | 489 | struct snd_soc_platform *platform = socdev->platform; |
| 491 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 490 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
| 492 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 491 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
| 493 | int ret = 0; | 492 | int ret = 0; |
| 494 | 493 | ||
| 495 | mutex_lock(&pcm_mutex); | 494 | mutex_lock(&pcm_mutex); |
| @@ -514,7 +513,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 514 | if (cpu_dai->ops.hw_params) { | 513 | if (cpu_dai->ops.hw_params) { |
| 515 | ret = cpu_dai->ops.hw_params(substream, params); | 514 | ret = cpu_dai->ops.hw_params(substream, params); |
| 516 | if (ret < 0) { | 515 | if (ret < 0) { |
| 517 | printk(KERN_ERR "asoc: can't set interface %s hw params\n", | 516 | printk(KERN_ERR "asoc: interface %s hw params failed\n", |
| 518 | cpu_dai->name); | 517 | cpu_dai->name); |
| 519 | goto interface_err; | 518 | goto interface_err; |
| 520 | } | 519 | } |
| @@ -523,7 +522,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 523 | if (platform->pcm_ops->hw_params) { | 522 | if (platform->pcm_ops->hw_params) { |
| 524 | ret = platform->pcm_ops->hw_params(substream, params); | 523 | ret = platform->pcm_ops->hw_params(substream, params); |
| 525 | if (ret < 0) { | 524 | if (ret < 0) { |
| 526 | printk(KERN_ERR "asoc: can't set platform %s hw params\n", | 525 | printk(KERN_ERR "asoc: platform %s hw params failed\n", |
| 527 | platform->name); | 526 | platform->name); |
| 528 | goto platform_err; | 527 | goto platform_err; |
| 529 | } | 528 | } |
| @@ -542,7 +541,7 @@ interface_err: | |||
| 542 | codec_dai->ops.hw_free(substream); | 541 | codec_dai->ops.hw_free(substream); |
| 543 | 542 | ||
| 544 | codec_err: | 543 | codec_err: |
| 545 | if(machine->ops && machine->ops->hw_free) | 544 | if (machine->ops && machine->ops->hw_free) |
| 546 | machine->ops->hw_free(substream); | 545 | machine->ops->hw_free(substream); |
| 547 | 546 | ||
| 548 | mutex_unlock(&pcm_mutex); | 547 | mutex_unlock(&pcm_mutex); |
| @@ -558,15 +557,15 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
| 558 | struct snd_soc_device *socdev = rtd->socdev; | 557 | struct snd_soc_device *socdev = rtd->socdev; |
| 559 | struct snd_soc_dai_link *machine = rtd->dai; | 558 | struct snd_soc_dai_link *machine = rtd->dai; |
| 560 | struct snd_soc_platform *platform = socdev->platform; | 559 | struct snd_soc_platform *platform = socdev->platform; |
| 561 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 560 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
| 562 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 561 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
| 563 | struct snd_soc_codec *codec = socdev->codec; | 562 | struct snd_soc_codec *codec = socdev->codec; |
| 564 | 563 | ||
| 565 | mutex_lock(&pcm_mutex); | 564 | mutex_lock(&pcm_mutex); |
| 566 | 565 | ||
| 567 | /* apply codec digital mute */ | 566 | /* apply codec digital mute */ |
| 568 | if (!codec->active && codec_dai->dai_ops.digital_mute) | 567 | if (!codec->active) |
| 569 | codec_dai->dai_ops.digital_mute(codec_dai, 1); | 568 | snd_soc_dai_digital_mute(codec_dai, 1); |
| 570 | 569 | ||
| 571 | /* free any machine hw params */ | 570 | /* free any machine hw params */ |
| 572 | if (machine->ops && machine->ops->hw_free) | 571 | if (machine->ops && machine->ops->hw_free) |
| @@ -593,8 +592,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 593 | struct snd_soc_device *socdev = rtd->socdev; | 592 | struct snd_soc_device *socdev = rtd->socdev; |
| 594 | struct snd_soc_dai_link *machine = rtd->dai; | 593 | struct snd_soc_dai_link *machine = rtd->dai; |
| 595 | struct snd_soc_platform *platform = socdev->platform; | 594 | struct snd_soc_platform *platform = socdev->platform; |
| 596 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 595 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
| 597 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 596 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
| 598 | int ret; | 597 | int ret; |
| 599 | 598 | ||
| 600 | if (codec_dai->ops.trigger) { | 599 | if (codec_dai->ops.trigger) { |
| @@ -631,16 +630,26 @@ static struct snd_pcm_ops soc_pcm_ops = { | |||
| 631 | /* powers down audio subsystem for suspend */ | 630 | /* powers down audio subsystem for suspend */ |
| 632 | static int soc_suspend(struct platform_device *pdev, pm_message_t state) | 631 | static int soc_suspend(struct platform_device *pdev, pm_message_t state) |
| 633 | { | 632 | { |
| 634 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 633 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 635 | struct snd_soc_machine *machine = socdev->machine; | 634 | struct snd_soc_machine *machine = socdev->machine; |
| 636 | struct snd_soc_platform *platform = socdev->platform; | 635 | struct snd_soc_platform *platform = socdev->platform; |
| 637 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | 636 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; |
| 638 | struct snd_soc_codec *codec = socdev->codec; | 637 | struct snd_soc_codec *codec = socdev->codec; |
| 639 | int i; | 638 | int i; |
| 640 | 639 | ||
| 640 | /* Due to the resume being scheduled into a workqueue we could | ||
| 641 | * suspend before that's finished - wait for it to complete. | ||
| 642 | */ | ||
| 643 | snd_power_lock(codec->card); | ||
| 644 | snd_power_wait(codec->card, SNDRV_CTL_POWER_D0); | ||
| 645 | snd_power_unlock(codec->card); | ||
| 646 | |||
| 647 | /* we're going to block userspace touching us until resume completes */ | ||
| 648 | snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot); | ||
| 649 | |||
| 641 | /* mute any active DAC's */ | 650 | /* mute any active DAC's */ |
| 642 | for(i = 0; i < machine->num_links; i++) { | 651 | for (i = 0; i < machine->num_links; i++) { |
| 643 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | 652 | struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; |
| 644 | if (dai->dai_ops.digital_mute && dai->playback.active) | 653 | if (dai->dai_ops.digital_mute && dai->playback.active) |
| 645 | dai->dai_ops.digital_mute(dai, 1); | 654 | dai->dai_ops.digital_mute(dai, 1); |
| 646 | } | 655 | } |
| @@ -652,8 +661,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 652 | if (machine->suspend_pre) | 661 | if (machine->suspend_pre) |
| 653 | machine->suspend_pre(pdev, state); | 662 | machine->suspend_pre(pdev, state); |
| 654 | 663 | ||
| 655 | for(i = 0; i < machine->num_links; i++) { | 664 | for (i = 0; i < machine->num_links; i++) { |
| 656 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 665 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
| 657 | if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) | 666 | if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) |
| 658 | cpu_dai->suspend(pdev, cpu_dai); | 667 | cpu_dai->suspend(pdev, cpu_dai); |
| 659 | if (platform->suspend) | 668 | if (platform->suspend) |
| @@ -662,9 +671,9 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 662 | 671 | ||
| 663 | /* close any waiting streams and save state */ | 672 | /* close any waiting streams and save state */ |
| 664 | run_delayed_work(&socdev->delayed_work); | 673 | run_delayed_work(&socdev->delayed_work); |
| 665 | codec->suspend_dapm_state = codec->dapm_state; | 674 | codec->suspend_bias_level = codec->bias_level; |
| 666 | 675 | ||
| 667 | for(i = 0; i < codec->num_dai; i++) { | 676 | for (i = 0; i < codec->num_dai; i++) { |
| 668 | char *stream = codec->dai[i].playback.stream_name; | 677 | char *stream = codec->dai[i].playback.stream_name; |
| 669 | if (stream != NULL) | 678 | if (stream != NULL) |
| 670 | snd_soc_dapm_stream_event(codec, stream, | 679 | snd_soc_dapm_stream_event(codec, stream, |
| @@ -678,8 +687,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 678 | if (codec_dev->suspend) | 687 | if (codec_dev->suspend) |
| 679 | codec_dev->suspend(pdev, state); | 688 | codec_dev->suspend(pdev, state); |
| 680 | 689 | ||
| 681 | for(i = 0; i < machine->num_links; i++) { | 690 | for (i = 0; i < machine->num_links; i++) { |
| 682 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 691 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
| 683 | if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) | 692 | if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) |
| 684 | cpu_dai->suspend(pdev, cpu_dai); | 693 | cpu_dai->suspend(pdev, cpu_dai); |
| 685 | } | 694 | } |
| @@ -690,21 +699,32 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
| 690 | return 0; | 699 | return 0; |
| 691 | } | 700 | } |
| 692 | 701 | ||
| 693 | /* powers up audio subsystem after a suspend */ | 702 | /* deferred resume work, so resume can complete before we finished |
| 694 | static int soc_resume(struct platform_device *pdev) | 703 | * setting our codec back up, which can be very slow on I2C |
| 704 | */ | ||
| 705 | static void soc_resume_deferred(struct work_struct *work) | ||
| 695 | { | 706 | { |
| 696 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 707 | struct snd_soc_device *socdev = container_of(work, |
| 697 | struct snd_soc_machine *machine = socdev->machine; | 708 | struct snd_soc_device, |
| 698 | struct snd_soc_platform *platform = socdev->platform; | 709 | deferred_resume_work); |
| 699 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | 710 | struct snd_soc_machine *machine = socdev->machine; |
| 711 | struct snd_soc_platform *platform = socdev->platform; | ||
| 712 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
| 700 | struct snd_soc_codec *codec = socdev->codec; | 713 | struct snd_soc_codec *codec = socdev->codec; |
| 714 | struct platform_device *pdev = to_platform_device(socdev->dev); | ||
| 701 | int i; | 715 | int i; |
| 702 | 716 | ||
| 717 | /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, | ||
| 718 | * so userspace apps are blocked from touching us | ||
| 719 | */ | ||
| 720 | |||
| 721 | dev_info(socdev->dev, "starting resume work\n"); | ||
| 722 | |||
| 703 | if (machine->resume_pre) | 723 | if (machine->resume_pre) |
| 704 | machine->resume_pre(pdev); | 724 | machine->resume_pre(pdev); |
| 705 | 725 | ||
| 706 | for(i = 0; i < machine->num_links; i++) { | 726 | for (i = 0; i < machine->num_links; i++) { |
| 707 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 727 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
| 708 | if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) | 728 | if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) |
| 709 | cpu_dai->resume(pdev, cpu_dai); | 729 | cpu_dai->resume(pdev, cpu_dai); |
| 710 | } | 730 | } |
| @@ -712,8 +732,8 @@ static int soc_resume(struct platform_device *pdev) | |||
| 712 | if (codec_dev->resume) | 732 | if (codec_dev->resume) |
| 713 | codec_dev->resume(pdev); | 733 | codec_dev->resume(pdev); |
| 714 | 734 | ||
| 715 | for(i = 0; i < codec->num_dai; i++) { | 735 | for (i = 0; i < codec->num_dai; i++) { |
| 716 | char* stream = codec->dai[i].playback.stream_name; | 736 | char *stream = codec->dai[i].playback.stream_name; |
| 717 | if (stream != NULL) | 737 | if (stream != NULL) |
| 718 | snd_soc_dapm_stream_event(codec, stream, | 738 | snd_soc_dapm_stream_event(codec, stream, |
| 719 | SND_SOC_DAPM_STREAM_RESUME); | 739 | SND_SOC_DAPM_STREAM_RESUME); |
| @@ -723,15 +743,15 @@ static int soc_resume(struct platform_device *pdev) | |||
| 723 | SND_SOC_DAPM_STREAM_RESUME); | 743 | SND_SOC_DAPM_STREAM_RESUME); |
| 724 | } | 744 | } |
| 725 | 745 | ||
| 726 | /* unmute any active DAC's */ | 746 | /* unmute any active DACs */ |
| 727 | for(i = 0; i < machine->num_links; i++) { | 747 | for (i = 0; i < machine->num_links; i++) { |
| 728 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | 748 | struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; |
| 729 | if (dai->dai_ops.digital_mute && dai->playback.active) | 749 | if (dai->dai_ops.digital_mute && dai->playback.active) |
| 730 | dai->dai_ops.digital_mute(dai, 0); | 750 | dai->dai_ops.digital_mute(dai, 0); |
| 731 | } | 751 | } |
| 732 | 752 | ||
| 733 | for(i = 0; i < machine->num_links; i++) { | 753 | for (i = 0; i < machine->num_links; i++) { |
| 734 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 754 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
| 735 | if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) | 755 | if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) |
| 736 | cpu_dai->resume(pdev, cpu_dai); | 756 | cpu_dai->resume(pdev, cpu_dai); |
| 737 | if (platform->resume) | 757 | if (platform->resume) |
| @@ -741,6 +761,22 @@ static int soc_resume(struct platform_device *pdev) | |||
| 741 | if (machine->resume_post) | 761 | if (machine->resume_post) |
| 742 | machine->resume_post(pdev); | 762 | machine->resume_post(pdev); |
| 743 | 763 | ||
| 764 | dev_info(socdev->dev, "resume work completed\n"); | ||
| 765 | |||
| 766 | /* userspace can access us now we are back as we were before */ | ||
| 767 | snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0); | ||
| 768 | } | ||
| 769 | |||
| 770 | /* powers up audio subsystem after a suspend */ | ||
| 771 | static int soc_resume(struct platform_device *pdev) | ||
| 772 | { | ||
| 773 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
| 774 | |||
| 775 | dev_info(socdev->dev, "scheduling resume work\n"); | ||
| 776 | |||
| 777 | if (!schedule_work(&socdev->deferred_resume_work)) | ||
| 778 | dev_err(socdev->dev, "work item may be lost\n"); | ||
| 779 | |||
| 744 | return 0; | 780 | return 0; |
| 745 | } | 781 | } |
| 746 | 782 | ||
| @@ -760,33 +796,38 @@ static int soc_probe(struct platform_device *pdev) | |||
| 760 | 796 | ||
| 761 | if (machine->probe) { | 797 | if (machine->probe) { |
| 762 | ret = machine->probe(pdev); | 798 | ret = machine->probe(pdev); |
| 763 | if(ret < 0) | 799 | if (ret < 0) |
| 764 | return ret; | 800 | return ret; |
| 765 | } | 801 | } |
| 766 | 802 | ||
| 767 | for (i = 0; i < machine->num_links; i++) { | 803 | for (i = 0; i < machine->num_links; i++) { |
| 768 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 804 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
| 769 | if (cpu_dai->probe) { | 805 | if (cpu_dai->probe) { |
| 770 | ret = cpu_dai->probe(pdev); | 806 | ret = cpu_dai->probe(pdev, cpu_dai); |
| 771 | if(ret < 0) | 807 | if (ret < 0) |
| 772 | goto cpu_dai_err; | 808 | goto cpu_dai_err; |
| 773 | } | 809 | } |
| 774 | } | 810 | } |
| 775 | 811 | ||
| 776 | if (codec_dev->probe) { | 812 | if (codec_dev->probe) { |
| 777 | ret = codec_dev->probe(pdev); | 813 | ret = codec_dev->probe(pdev); |
| 778 | if(ret < 0) | 814 | if (ret < 0) |
| 779 | goto cpu_dai_err; | 815 | goto cpu_dai_err; |
| 780 | } | 816 | } |
| 781 | 817 | ||
| 782 | if (platform->probe) { | 818 | if (platform->probe) { |
| 783 | ret = platform->probe(pdev); | 819 | ret = platform->probe(pdev); |
| 784 | if(ret < 0) | 820 | if (ret < 0) |
| 785 | goto platform_err; | 821 | goto platform_err; |
| 786 | } | 822 | } |
| 787 | 823 | ||
| 788 | /* DAPM stream work */ | 824 | /* DAPM stream work */ |
| 789 | INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); | 825 | INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); |
| 826 | #ifdef CONFIG_PM | ||
| 827 | /* deferred resume work */ | ||
| 828 | INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred); | ||
| 829 | #endif | ||
| 830 | |||
| 790 | return 0; | 831 | return 0; |
| 791 | 832 | ||
| 792 | platform_err: | 833 | platform_err: |
| @@ -795,9 +836,9 @@ platform_err: | |||
| 795 | 836 | ||
| 796 | cpu_dai_err: | 837 | cpu_dai_err: |
| 797 | for (i--; i >= 0; i--) { | 838 | for (i--; i >= 0; i--) { |
| 798 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 839 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
| 799 | if (cpu_dai->remove) | 840 | if (cpu_dai->remove) |
| 800 | cpu_dai->remove(pdev); | 841 | cpu_dai->remove(pdev, cpu_dai); |
| 801 | } | 842 | } |
| 802 | 843 | ||
| 803 | if (machine->remove) | 844 | if (machine->remove) |
| @@ -824,9 +865,9 @@ static int soc_remove(struct platform_device *pdev) | |||
| 824 | codec_dev->remove(pdev); | 865 | codec_dev->remove(pdev); |
| 825 | 866 | ||
| 826 | for (i = 0; i < machine->num_links; i++) { | 867 | for (i = 0; i < machine->num_links; i++) { |
| 827 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 868 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
| 828 | if (cpu_dai->remove) | 869 | if (cpu_dai->remove) |
| 829 | cpu_dai->remove(pdev); | 870 | cpu_dai->remove(pdev, cpu_dai); |
| 830 | } | 871 | } |
| 831 | 872 | ||
| 832 | if (machine->remove) | 873 | if (machine->remove) |
| @@ -852,8 +893,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
| 852 | struct snd_soc_dai_link *dai_link, int num) | 893 | struct snd_soc_dai_link *dai_link, int num) |
| 853 | { | 894 | { |
| 854 | struct snd_soc_codec *codec = socdev->codec; | 895 | struct snd_soc_codec *codec = socdev->codec; |
| 855 | struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai; | 896 | struct snd_soc_dai *codec_dai = dai_link->codec_dai; |
| 856 | struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai; | 897 | struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; |
| 857 | struct snd_soc_pcm_runtime *rtd; | 898 | struct snd_soc_pcm_runtime *rtd; |
| 858 | struct snd_pcm *pcm; | 899 | struct snd_pcm *pcm; |
| 859 | char new_name[64]; | 900 | char new_name[64]; |
| @@ -868,7 +909,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
| 868 | codec_dai->codec = socdev->codec; | 909 | codec_dai->codec = socdev->codec; |
| 869 | 910 | ||
| 870 | /* check client and interface hw capabilities */ | 911 | /* check client and interface hw capabilities */ |
| 871 | sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, | 912 | sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name, |
| 872 | get_dai_name(cpu_dai->type), num); | 913 | get_dai_name(cpu_dai->type), num); |
| 873 | 914 | ||
| 874 | if (codec_dai->playback.channels_min) | 915 | if (codec_dai->playback.channels_min) |
| @@ -879,7 +920,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
| 879 | ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, | 920 | ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, |
| 880 | capture, &pcm); | 921 | capture, &pcm); |
| 881 | if (ret < 0) { | 922 | if (ret < 0) { |
| 882 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | 923 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", |
| 924 | codec->name); | ||
| 883 | kfree(rtd); | 925 | kfree(rtd); |
| 884 | return ret; | 926 | return ret; |
| 885 | } | 927 | } |
| @@ -928,8 +970,9 @@ static ssize_t codec_reg_show(struct device *dev, | |||
| 928 | step = codec->reg_cache_step; | 970 | step = codec->reg_cache_step; |
| 929 | 971 | ||
| 930 | count += sprintf(buf, "%s registers\n", codec->name); | 972 | count += sprintf(buf, "%s registers\n", codec->name); |
| 931 | for(i = 0; i < codec->reg_cache_size; i += step) | 973 | for (i = 0; i < codec->reg_cache_size; i += step) |
| 932 | count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i)); | 974 | count += sprintf(buf + count, "%2x: %4x\n", i, |
| 975 | codec->read(codec, i)); | ||
| 933 | 976 | ||
| 934 | return count; | 977 | return count; |
| 935 | } | 978 | } |
| @@ -1072,7 +1115,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) | |||
| 1072 | strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); | 1115 | strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); |
| 1073 | 1116 | ||
| 1074 | /* create the pcms */ | 1117 | /* create the pcms */ |
| 1075 | for(i = 0; i < machine->num_links; i++) { | 1118 | for (i = 0; i < machine->num_links; i++) { |
| 1076 | ret = soc_new_pcm(socdev, &machine->dai_link[i], i); | 1119 | ret = soc_new_pcm(socdev, &machine->dai_link[i], i); |
| 1077 | if (ret < 0) { | 1120 | if (ret < 0) { |
| 1078 | printk(KERN_ERR "asoc: can't create pcm %s\n", | 1121 | printk(KERN_ERR "asoc: can't create pcm %s\n", |
| @@ -1102,7 +1145,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
| 1102 | struct snd_soc_machine *machine = socdev->machine; | 1145 | struct snd_soc_machine *machine = socdev->machine; |
| 1103 | int ret = 0, i, ac97 = 0, err = 0; | 1146 | int ret = 0, i, ac97 = 0, err = 0; |
| 1104 | 1147 | ||
| 1105 | for(i = 0; i < machine->num_links; i++) { | 1148 | for (i = 0; i < machine->num_links; i++) { |
| 1106 | if (socdev->machine->dai_link[i].init) { | 1149 | if (socdev->machine->dai_link[i].init) { |
| 1107 | err = socdev->machine->dai_link[i].init(codec); | 1150 | err = socdev->machine->dai_link[i].init(codec); |
| 1108 | if (err < 0) { | 1151 | if (err < 0) { |
| @@ -1111,7 +1154,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
| 1111 | continue; | 1154 | continue; |
| 1112 | } | 1155 | } |
| 1113 | } | 1156 | } |
| 1114 | if (socdev->machine->dai_link[i].codec_dai->type == | 1157 | if (socdev->machine->dai_link[i].codec_dai->type == |
| 1115 | SND_SOC_DAI_AC97_BUS) | 1158 | SND_SOC_DAI_AC97_BUS) |
| 1116 | ac97 = 1; | 1159 | ac97 = 1; |
| 1117 | } | 1160 | } |
| @@ -1122,7 +1165,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
| 1122 | 1165 | ||
| 1123 | ret = snd_card_register(codec->card); | 1166 | ret = snd_card_register(codec->card); |
| 1124 | if (ret < 0) { | 1167 | if (ret < 0) { |
| 1125 | printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", | 1168 | printk(KERN_ERR "asoc: failed to register soundcard for %s\n", |
| 1126 | codec->name); | 1169 | codec->name); |
| 1127 | goto out; | 1170 | goto out; |
| 1128 | } | 1171 | } |
| @@ -1146,7 +1189,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
| 1146 | 1189 | ||
| 1147 | err = device_create_file(socdev->dev, &dev_attr_codec_reg); | 1190 | err = device_create_file(socdev->dev, &dev_attr_codec_reg); |
| 1148 | if (err < 0) | 1191 | if (err < 0) |
| 1149 | printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); | 1192 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); |
| 1150 | 1193 | ||
| 1151 | mutex_unlock(&codec->mutex); | 1194 | mutex_unlock(&codec->mutex); |
| 1152 | 1195 | ||
| @@ -1166,13 +1209,13 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) | |||
| 1166 | { | 1209 | { |
| 1167 | struct snd_soc_codec *codec = socdev->codec; | 1210 | struct snd_soc_codec *codec = socdev->codec; |
| 1168 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1211 | #ifdef CONFIG_SND_SOC_AC97_BUS |
| 1169 | struct snd_soc_codec_dai *codec_dai; | 1212 | struct snd_soc_dai *codec_dai; |
| 1170 | int i; | 1213 | int i; |
| 1171 | #endif | 1214 | #endif |
| 1172 | 1215 | ||
| 1173 | mutex_lock(&codec->mutex); | 1216 | mutex_lock(&codec->mutex); |
| 1174 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1217 | #ifdef CONFIG_SND_SOC_AC97_BUS |
| 1175 | for(i = 0; i < codec->num_dai; i++) { | 1218 | for (i = 0; i < codec->num_dai; i++) { |
| 1176 | codec_dai = &codec->dai[i]; | 1219 | codec_dai = &codec->dai[i]; |
| 1177 | if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { | 1220 | if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { |
| 1178 | soc_ac97_dev_unregister(codec); | 1221 | soc_ac97_dev_unregister(codec); |
| @@ -1282,7 +1325,8 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
| 1282 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | 1325 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) |
| 1283 | ; | 1326 | ; |
| 1284 | val = snd_soc_read(codec, e->reg); | 1327 | val = snd_soc_read(codec, e->reg); |
| 1285 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); | 1328 | ucontrol->value.enumerated.item[0] |
| 1329 | = (val >> e->shift_l) & (bitmask - 1); | ||
| 1286 | if (e->shift_l != e->shift_r) | 1330 | if (e->shift_l != e->shift_r) |
| 1287 | ucontrol->value.enumerated.item[1] = | 1331 | ucontrol->value.enumerated.item[1] = |
| 1288 | (val >> e->shift_r) & (bitmask - 1); | 1332 | (val >> e->shift_r) & (bitmask - 1); |
| @@ -1576,7 +1620,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
| 1576 | val = val << shift; | 1620 | val = val << shift; |
| 1577 | val2 = val2 << shift; | 1621 | val2 = val2 << shift; |
| 1578 | 1622 | ||
| 1579 | if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) | 1623 | err = snd_soc_update_bits(codec, reg, val_mask, val); |
| 1624 | if (err < 0) | ||
| 1580 | return err; | 1625 | return err; |
| 1581 | 1626 | ||
| 1582 | err = snd_soc_update_bits(codec, reg2, val_mask, val2); | 1627 | err = snd_soc_update_bits(codec, reg2, val_mask, val2); |
| @@ -1584,6 +1629,204 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
| 1584 | } | 1629 | } |
| 1585 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); | 1630 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); |
| 1586 | 1631 | ||
| 1632 | /** | ||
| 1633 | * snd_soc_info_volsw_s8 - signed mixer info callback | ||
| 1634 | * @kcontrol: mixer control | ||
| 1635 | * @uinfo: control element information | ||
| 1636 | * | ||
| 1637 | * Callback to provide information about a signed mixer control. | ||
| 1638 | * | ||
| 1639 | * Returns 0 for success. | ||
| 1640 | */ | ||
| 1641 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | ||
| 1642 | struct snd_ctl_elem_info *uinfo) | ||
| 1643 | { | ||
| 1644 | int max = (signed char)((kcontrol->private_value >> 16) & 0xff); | ||
| 1645 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | ||
| 1646 | |||
| 1647 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 1648 | uinfo->count = 2; | ||
| 1649 | uinfo->value.integer.min = 0; | ||
| 1650 | uinfo->value.integer.max = max-min; | ||
| 1651 | return 0; | ||
| 1652 | } | ||
| 1653 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | ||
| 1654 | |||
| 1655 | /** | ||
| 1656 | * snd_soc_get_volsw_s8 - signed mixer get callback | ||
| 1657 | * @kcontrol: mixer control | ||
| 1658 | * @uinfo: control element information | ||
| 1659 | * | ||
| 1660 | * Callback to get the value of a signed mixer control. | ||
| 1661 | * | ||
| 1662 | * Returns 0 for success. | ||
| 1663 | */ | ||
| 1664 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | ||
| 1665 | struct snd_ctl_elem_value *ucontrol) | ||
| 1666 | { | ||
| 1667 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 1668 | int reg = kcontrol->private_value & 0xff; | ||
| 1669 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | ||
| 1670 | int val = snd_soc_read(codec, reg); | ||
| 1671 | |||
| 1672 | ucontrol->value.integer.value[0] = | ||
| 1673 | ((signed char)(val & 0xff))-min; | ||
| 1674 | ucontrol->value.integer.value[1] = | ||
| 1675 | ((signed char)((val >> 8) & 0xff))-min; | ||
| 1676 | return 0; | ||
| 1677 | } | ||
| 1678 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); | ||
| 1679 | |||
| 1680 | /** | ||
| 1681 | * snd_soc_put_volsw_sgn - signed mixer put callback | ||
| 1682 | * @kcontrol: mixer control | ||
| 1683 | * @uinfo: control element information | ||
| 1684 | * | ||
| 1685 | * Callback to set the value of a signed mixer control. | ||
| 1686 | * | ||
| 1687 | * Returns 0 for success. | ||
| 1688 | */ | ||
| 1689 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | ||
| 1690 | struct snd_ctl_elem_value *ucontrol) | ||
| 1691 | { | ||
| 1692 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 1693 | int reg = kcontrol->private_value & 0xff; | ||
| 1694 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | ||
| 1695 | unsigned short val; | ||
| 1696 | |||
| 1697 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | ||
| 1698 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | ||
| 1699 | |||
| 1700 | return snd_soc_update_bits(codec, reg, 0xffff, val); | ||
| 1701 | } | ||
| 1702 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | ||
| 1703 | |||
| 1704 | /** | ||
| 1705 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | ||
| 1706 | * @dai: DAI | ||
| 1707 | * @clk_id: DAI specific clock ID | ||
| 1708 | * @freq: new clock frequency in Hz | ||
| 1709 | * @dir: new clock direction - input/output. | ||
| 1710 | * | ||
| 1711 | * Configures the DAI master (MCLK) or system (SYSCLK) clocking. | ||
| 1712 | */ | ||
| 1713 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
| 1714 | unsigned int freq, int dir) | ||
| 1715 | { | ||
| 1716 | if (dai->dai_ops.set_sysclk) | ||
| 1717 | return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir); | ||
| 1718 | else | ||
| 1719 | return -EINVAL; | ||
| 1720 | } | ||
| 1721 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); | ||
| 1722 | |||
| 1723 | /** | ||
| 1724 | * snd_soc_dai_set_clkdiv - configure DAI clock dividers. | ||
| 1725 | * @dai: DAI | ||
| 1726 | * @clk_id: DAI specific clock divider ID | ||
| 1727 | * @div: new clock divisor. | ||
| 1728 | * | ||
| 1729 | * Configures the clock dividers. This is used to derive the best DAI bit and | ||
| 1730 | * frame clocks from the system or master clock. It's best to set the DAI bit | ||
| 1731 | * and frame clocks as low as possible to save system power. | ||
| 1732 | */ | ||
| 1733 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, | ||
| 1734 | int div_id, int div) | ||
| 1735 | { | ||
| 1736 | if (dai->dai_ops.set_clkdiv) | ||
| 1737 | return dai->dai_ops.set_clkdiv(dai, div_id, div); | ||
| 1738 | else | ||
| 1739 | return -EINVAL; | ||
| 1740 | } | ||
| 1741 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); | ||
| 1742 | |||
| 1743 | /** | ||
| 1744 | * snd_soc_dai_set_pll - configure DAI PLL. | ||
| 1745 | * @dai: DAI | ||
| 1746 | * @pll_id: DAI specific PLL ID | ||
| 1747 | * @freq_in: PLL input clock frequency in Hz | ||
| 1748 | * @freq_out: requested PLL output clock frequency in Hz | ||
| 1749 | * | ||
| 1750 | * Configures and enables PLL to generate output clock based on input clock. | ||
| 1751 | */ | ||
| 1752 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, | ||
| 1753 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
| 1754 | { | ||
| 1755 | if (dai->dai_ops.set_pll) | ||
| 1756 | return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out); | ||
| 1757 | else | ||
| 1758 | return -EINVAL; | ||
| 1759 | } | ||
| 1760 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); | ||
| 1761 | |||
| 1762 | /** | ||
| 1763 | * snd_soc_dai_set_fmt - configure DAI hardware audio format. | ||
| 1764 | * @dai: DAI | ||
| 1765 | * @clk_id: DAI specific clock ID | ||
| 1766 | * @fmt: SND_SOC_DAIFMT_ format value. | ||
| 1767 | * | ||
| 1768 | * Configures the DAI hardware format and clocking. | ||
| 1769 | */ | ||
| 1770 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
| 1771 | { | ||
| 1772 | if (dai->dai_ops.set_fmt) | ||
| 1773 | return dai->dai_ops.set_fmt(dai, fmt); | ||
| 1774 | else | ||
| 1775 | return -EINVAL; | ||
| 1776 | } | ||
| 1777 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | ||
| 1778 | |||
| 1779 | /** | ||
| 1780 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. | ||
| 1781 | * @dai: DAI | ||
| 1782 | * @mask: DAI specific mask representing used slots. | ||
| 1783 | * @slots: Number of slots in use. | ||
| 1784 | * | ||
| 1785 | * Configures a DAI for TDM operation. Both mask and slots are codec and DAI | ||
| 1786 | * specific. | ||
| 1787 | */ | ||
| 1788 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | ||
| 1789 | unsigned int mask, int slots) | ||
| 1790 | { | ||
| 1791 | if (dai->dai_ops.set_sysclk) | ||
| 1792 | return dai->dai_ops.set_tdm_slot(dai, mask, slots); | ||
| 1793 | else | ||
| 1794 | return -EINVAL; | ||
| 1795 | } | ||
| 1796 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | ||
| 1797 | |||
| 1798 | /** | ||
| 1799 | * snd_soc_dai_set_tristate - configure DAI system or master clock. | ||
| 1800 | * @dai: DAI | ||
| 1801 | * @tristate: tristate enable | ||
| 1802 | * | ||
| 1803 | * Tristates the DAI so that others can use it. | ||
| 1804 | */ | ||
| 1805 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
| 1806 | { | ||
| 1807 | if (dai->dai_ops.set_sysclk) | ||
| 1808 | return dai->dai_ops.set_tristate(dai, tristate); | ||
| 1809 | else | ||
| 1810 | return -EINVAL; | ||
| 1811 | } | ||
| 1812 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); | ||
| 1813 | |||
| 1814 | /** | ||
| 1815 | * snd_soc_dai_digital_mute - configure DAI system or master clock. | ||
| 1816 | * @dai: DAI | ||
| 1817 | * @mute: mute enable | ||
| 1818 | * | ||
| 1819 | * Mutes the DAI DAC. | ||
| 1820 | */ | ||
| 1821 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) | ||
| 1822 | { | ||
| 1823 | if (dai->dai_ops.digital_mute) | ||
| 1824 | return dai->dai_ops.digital_mute(dai, mute); | ||
| 1825 | else | ||
| 1826 | return -EINVAL; | ||
| 1827 | } | ||
| 1828 | EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); | ||
| 1829 | |||
| 1587 | static int __devinit snd_soc_init(void) | 1830 | static int __devinit snd_soc_init(void) |
| 1588 | { | 1831 | { |
| 1589 | printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); | 1832 | printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); |
| @@ -1592,7 +1835,7 @@ static int __devinit snd_soc_init(void) | |||
| 1592 | 1835 | ||
| 1593 | static void snd_soc_exit(void) | 1836 | static void snd_soc_exit(void) |
| 1594 | { | 1837 | { |
| 1595 | platform_driver_unregister(&soc_driver); | 1838 | platform_driver_unregister(&soc_driver); |
| 1596 | } | 1839 | } |
| 1597 | 1840 | ||
| 1598 | module_init(snd_soc_init); | 1841 | module_init(snd_soc_init); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index af3326c63504..2c87061c2a6b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
| @@ -10,11 +10,6 @@ | |||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
| 11 | * option) any later version. | 11 | * option) any later version. |
| 12 | * | 12 | * |
| 13 | * Revision history | ||
| 14 | * 12th Aug 2005 Initial version. | ||
| 15 | * 25th Oct 2005 Implemented path power domain. | ||
| 16 | * 18th Dec 2005 Implemented machine and stream level power domain. | ||
| 17 | * | ||
| 18 | * Features: | 13 | * Features: |
| 19 | * o Changes power status of internal codec blocks depending on the | 14 | * o Changes power status of internal codec blocks depending on the |
| 20 | * dynamic configuration of codec internal audio paths and active | 15 | * dynamic configuration of codec internal audio paths and active |
| @@ -50,23 +45,10 @@ | |||
| 50 | #include <sound/initval.h> | 45 | #include <sound/initval.h> |
| 51 | 46 | ||
| 52 | /* debug */ | 47 | /* debug */ |
| 53 | #define DAPM_DEBUG 0 | 48 | #ifdef DEBUG |
| 54 | #if DAPM_DEBUG | ||
| 55 | #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) | 49 | #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) |
| 56 | #define dbg(format, arg...) printk(format, ## arg) | ||
| 57 | #else | 50 | #else |
| 58 | #define dump_dapm(codec, action) | 51 | #define dump_dapm(codec, action) |
| 59 | #define dbg(format, arg...) | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #define POP_DEBUG 0 | ||
| 63 | #if POP_DEBUG | ||
| 64 | #define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */ | ||
| 65 | #define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time)) | ||
| 66 | #define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME) | ||
| 67 | #else | ||
| 68 | #define pop_dbg(format, arg...) | ||
| 69 | #define pop_wait(time) | ||
| 70 | #endif | 52 | #endif |
| 71 | 53 | ||
| 72 | /* dapm power sequences - make this per codec in the future */ | 54 | /* dapm power sequences - make this per codec in the future */ |
| @@ -85,6 +67,28 @@ static int dapm_status = 1; | |||
| 85 | module_param(dapm_status, int, 0); | 67 | module_param(dapm_status, int, 0); |
| 86 | MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); | 68 | MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); |
| 87 | 69 | ||
| 70 | static unsigned int pop_time; | ||
| 71 | |||
| 72 | static void pop_wait(void) | ||
| 73 | { | ||
| 74 | if (pop_time) | ||
| 75 | schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void pop_dbg(const char *fmt, ...) | ||
| 79 | { | ||
| 80 | va_list args; | ||
| 81 | |||
| 82 | va_start(args, fmt); | ||
| 83 | |||
| 84 | if (pop_time) { | ||
| 85 | vprintk(fmt, args); | ||
| 86 | pop_wait(); | ||
| 87 | } | ||
| 88 | |||
| 89 | va_end(args); | ||
| 90 | } | ||
| 91 | |||
| 88 | /* create a new dapm widget */ | 92 | /* create a new dapm widget */ |
| 89 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | 93 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( |
| 90 | const struct snd_soc_dapm_widget *_widget) | 94 | const struct snd_soc_dapm_widget *_widget) |
| @@ -222,11 +226,12 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget) | |||
| 222 | change = old != new; | 226 | change = old != new; |
| 223 | if (change) { | 227 | if (change) { |
| 224 | pop_dbg("pop test %s : %s in %d ms\n", widget->name, | 228 | pop_dbg("pop test %s : %s in %d ms\n", widget->name, |
| 225 | widget->power ? "on" : "off", POP_TIME); | 229 | widget->power ? "on" : "off", pop_time); |
| 226 | snd_soc_write(codec, widget->reg, new); | 230 | snd_soc_write(codec, widget->reg, new); |
| 227 | pop_wait(POP_TIME); | 231 | pop_wait(); |
| 228 | } | 232 | } |
| 229 | dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change); | 233 | pr_debug("reg %x old %x new %x change %d\n", widget->reg, |
| 234 | old, new, change); | ||
| 230 | return change; | 235 | return change; |
| 231 | } | 236 | } |
| 232 | 237 | ||
| @@ -448,6 +453,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | |||
| 448 | } | 453 | } |
| 449 | 454 | ||
| 450 | /* | 455 | /* |
| 456 | * Handler for generic register modifier widget. | ||
| 457 | */ | ||
| 458 | int dapm_reg_event(struct snd_soc_dapm_widget *w, | ||
| 459 | struct snd_kcontrol *kcontrol, int event) | ||
| 460 | { | ||
| 461 | unsigned int val; | ||
| 462 | |||
| 463 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
| 464 | val = w->on_val; | ||
| 465 | else | ||
| 466 | val = w->off_val; | ||
| 467 | |||
| 468 | snd_soc_update_bits(w->codec, -(w->reg + 1), | ||
| 469 | w->mask << w->shift, val << w->shift); | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | /* | ||
| 451 | * Scan each dapm widget for complete audio path. | 475 | * Scan each dapm widget for complete audio path. |
| 452 | * A complete path is a route that has valid endpoints i.e.:- | 476 | * A complete path is a route that has valid endpoints i.e.:- |
| 453 | * | 477 | * |
| @@ -565,8 +589,8 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
| 565 | /* call any power change event handlers */ | 589 | /* call any power change event handlers */ |
| 566 | if (power_change) { | 590 | if (power_change) { |
| 567 | if (w->event) { | 591 | if (w->event) { |
| 568 | dbg("power %s event for %s flags %x\n", | 592 | pr_debug("power %s event for %s flags %x\n", |
| 569 | w->power ? "on" : "off", w->name, w->event_flags); | 593 | w->power ? "on" : "off", w->name, w->event_flags); |
| 570 | if (power) { | 594 | if (power) { |
| 571 | /* power up event */ | 595 | /* power up event */ |
| 572 | if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { | 596 | if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { |
| @@ -608,7 +632,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
| 608 | return ret; | 632 | return ret; |
| 609 | } | 633 | } |
| 610 | 634 | ||
| 611 | #if DAPM_DEBUG | 635 | #ifdef DEBUG |
| 612 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | 636 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) |
| 613 | { | 637 | { |
| 614 | struct snd_soc_dapm_widget *w; | 638 | struct snd_soc_dapm_widget *w; |
| @@ -693,8 +717,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
| 693 | path->connect = 0; /* old connection must be powered down */ | 717 | path->connect = 0; /* old connection must be powered down */ |
| 694 | } | 718 | } |
| 695 | 719 | ||
| 696 | if (found) | 720 | if (found) { |
| 697 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 721 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
| 722 | dump_dapm(widget->codec, "mux power update"); | ||
| 723 | } | ||
| 698 | 724 | ||
| 699 | return 0; | 725 | return 0; |
| 700 | } | 726 | } |
| @@ -730,8 +756,10 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
| 730 | break; | 756 | break; |
| 731 | } | 757 | } |
| 732 | 758 | ||
| 733 | if (found) | 759 | if (found) { |
| 734 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 760 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
| 761 | dump_dapm(widget->codec, "mixer power update"); | ||
| 762 | } | ||
| 735 | 763 | ||
| 736 | return 0; | 764 | return 0; |
| 737 | } | 765 | } |
| @@ -768,21 +796,18 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
| 768 | } | 796 | } |
| 769 | } | 797 | } |
| 770 | 798 | ||
| 771 | switch(codec->dapm_state){ | 799 | switch (codec->bias_level) { |
| 772 | case SNDRV_CTL_POWER_D0: | 800 | case SND_SOC_BIAS_ON: |
| 773 | state = "D0"; | 801 | state = "On"; |
| 774 | break; | 802 | break; |
| 775 | case SNDRV_CTL_POWER_D1: | 803 | case SND_SOC_BIAS_PREPARE: |
| 776 | state = "D1"; | 804 | state = "Prepare"; |
| 777 | break; | 805 | break; |
| 778 | case SNDRV_CTL_POWER_D2: | 806 | case SND_SOC_BIAS_STANDBY: |
| 779 | state = "D2"; | 807 | state = "Standby"; |
| 780 | break; | 808 | break; |
| 781 | case SNDRV_CTL_POWER_D3hot: | 809 | case SND_SOC_BIAS_OFF: |
| 782 | state = "D3hot"; | 810 | state = "Off"; |
| 783 | break; | ||
| 784 | case SNDRV_CTL_POWER_D3cold: | ||
| 785 | state = "D3cold"; | ||
| 786 | break; | 811 | break; |
| 787 | } | 812 | } |
| 788 | count += sprintf(buf + count, "PM State: %s\n", state); | 813 | count += sprintf(buf + count, "PM State: %s\n", state); |
| @@ -792,20 +817,51 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
| 792 | 817 | ||
| 793 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); | 818 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); |
| 794 | 819 | ||
| 820 | /* pop/click delay times */ | ||
| 821 | static ssize_t dapm_pop_time_show(struct device *dev, | ||
| 822 | struct device_attribute *attr, char *buf) | ||
| 823 | { | ||
| 824 | return sprintf(buf, "%d\n", pop_time); | ||
| 825 | } | ||
| 826 | |||
| 827 | static ssize_t dapm_pop_time_store(struct device *dev, | ||
| 828 | struct device_attribute *attr, | ||
| 829 | const char *buf, size_t count) | ||
| 830 | |||
| 831 | { | ||
| 832 | unsigned long val; | ||
| 833 | |||
| 834 | if (strict_strtoul(buf, 10, &val) >= 0) | ||
| 835 | pop_time = val; | ||
| 836 | else | ||
| 837 | printk(KERN_ERR "Unable to parse pop_time setting\n"); | ||
| 838 | |||
| 839 | return count; | ||
| 840 | } | ||
| 841 | |||
| 842 | static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show, | ||
| 843 | dapm_pop_time_store); | ||
| 844 | |||
| 795 | int snd_soc_dapm_sys_add(struct device *dev) | 845 | int snd_soc_dapm_sys_add(struct device *dev) |
| 796 | { | 846 | { |
| 797 | int ret = 0; | 847 | int ret = 0; |
| 798 | 848 | ||
| 799 | if (dapm_status) | 849 | if (dapm_status) { |
| 800 | ret = device_create_file(dev, &dev_attr_dapm_widget); | 850 | ret = device_create_file(dev, &dev_attr_dapm_widget); |
| 801 | 851 | ||
| 852 | if (ret == 0) | ||
| 853 | ret = device_create_file(dev, &dev_attr_dapm_pop_time); | ||
| 854 | } | ||
| 855 | |||
| 802 | return ret; | 856 | return ret; |
| 803 | } | 857 | } |
| 804 | 858 | ||
| 805 | static void snd_soc_dapm_sys_remove(struct device *dev) | 859 | static void snd_soc_dapm_sys_remove(struct device *dev) |
| 806 | { | 860 | { |
| 807 | if (dapm_status) | 861 | if (dapm_status) { |
| 862 | device_remove_file(dev, &dev_attr_dapm_pop_time); | ||
| 808 | device_remove_file(dev, &dev_attr_dapm_widget); | 863 | device_remove_file(dev, &dev_attr_dapm_widget); |
| 864 | } | ||
| 809 | } | 865 | } |
| 810 | 866 | ||
| 811 | /* free all dapm widgets and resources */ | 867 | /* free all dapm widgets and resources */ |
| @@ -826,8 +882,25 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) | |||
| 826 | } | 882 | } |
| 827 | } | 883 | } |
| 828 | 884 | ||
| 885 | static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | ||
| 886 | char *pin, int status) | ||
| 887 | { | ||
| 888 | struct snd_soc_dapm_widget *w; | ||
| 889 | |||
| 890 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
| 891 | if (!strcmp(w->name, pin)) { | ||
| 892 | pr_debug("dapm: %s: pin %s\n", codec->name, pin); | ||
| 893 | w->connected = status; | ||
| 894 | return 0; | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin); | ||
| 899 | return -EINVAL; | ||
| 900 | } | ||
| 901 | |||
| 829 | /** | 902 | /** |
| 830 | * snd_soc_dapm_sync_endpoints - scan and power dapm paths | 903 | * snd_soc_dapm_sync - scan and power dapm paths |
| 831 | * @codec: audio codec | 904 | * @codec: audio codec |
| 832 | * | 905 | * |
| 833 | * Walks all dapm audio paths and powers widgets according to their | 906 | * Walks all dapm audio paths and powers widgets according to their |
| @@ -835,27 +908,16 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) | |||
| 835 | * | 908 | * |
| 836 | * Returns 0 for success. | 909 | * Returns 0 for success. |
| 837 | */ | 910 | */ |
| 838 | int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec) | 911 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) |
| 839 | { | 912 | { |
| 840 | return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 913 | int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); |
| 914 | dump_dapm(codec, "sync"); | ||
| 915 | return ret; | ||
| 841 | } | 916 | } |
| 842 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints); | 917 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
| 843 | 918 | ||
| 844 | /** | 919 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, |
| 845 | * snd_soc_dapm_connect_input - connect dapm widgets | 920 | const char *sink, const char *control, const char *source) |
| 846 | * @codec: audio codec | ||
| 847 | * @sink: name of target widget | ||
| 848 | * @control: mixer control name | ||
| 849 | * @source: name of source name | ||
| 850 | * | ||
| 851 | * Connects 2 dapm widgets together via a named audio path. The sink is | ||
| 852 | * the widget receiving the audio signal, whilst the source is the sender | ||
| 853 | * of the audio signal. | ||
| 854 | * | ||
| 855 | * Returns 0 for success else error. | ||
| 856 | */ | ||
| 857 | int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, | ||
| 858 | const char * control, const char *source) | ||
| 859 | { | 921 | { |
| 860 | struct snd_soc_dapm_path *path; | 922 | struct snd_soc_dapm_path *path; |
| 861 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 923 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
| @@ -957,9 +1019,64 @@ err: | |||
| 957 | kfree(path); | 1019 | kfree(path); |
| 958 | return ret; | 1020 | return ret; |
| 959 | } | 1021 | } |
| 1022 | |||
| 1023 | /** | ||
| 1024 | * snd_soc_dapm_connect_input - connect dapm widgets | ||
| 1025 | * @codec: audio codec | ||
| 1026 | * @sink: name of target widget | ||
| 1027 | * @control: mixer control name | ||
| 1028 | * @source: name of source name | ||
| 1029 | * | ||
| 1030 | * Connects 2 dapm widgets together via a named audio path. The sink is | ||
| 1031 | * the widget receiving the audio signal, whilst the source is the sender | ||
| 1032 | * of the audio signal. | ||
| 1033 | * | ||
| 1034 | * This function has been deprecated in favour of snd_soc_dapm_add_routes(). | ||
| 1035 | * | ||
| 1036 | * Returns 0 for success else error. | ||
| 1037 | */ | ||
| 1038 | int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, | ||
| 1039 | const char *control, const char *source) | ||
| 1040 | { | ||
| 1041 | return snd_soc_dapm_add_route(codec, sink, control, source); | ||
| 1042 | } | ||
| 960 | EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); | 1043 | EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); |
| 961 | 1044 | ||
| 962 | /** | 1045 | /** |
| 1046 | * snd_soc_dapm_add_routes - Add routes between DAPM widgets | ||
| 1047 | * @codec: codec | ||
| 1048 | * @route: audio routes | ||
| 1049 | * @num: number of routes | ||
| 1050 | * | ||
| 1051 | * Connects 2 dapm widgets together via a named audio path. The sink is | ||
| 1052 | * the widget receiving the audio signal, whilst the source is the sender | ||
| 1053 | * of the audio signal. | ||
| 1054 | * | ||
| 1055 | * Returns 0 for success else error. On error all resources can be freed | ||
| 1056 | * with a call to snd_soc_card_free(). | ||
| 1057 | */ | ||
| 1058 | int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | ||
| 1059 | const struct snd_soc_dapm_route *route, int num) | ||
| 1060 | { | ||
| 1061 | int i, ret; | ||
| 1062 | |||
| 1063 | for (i = 0; i < num; i++) { | ||
| 1064 | ret = snd_soc_dapm_add_route(codec, route->sink, | ||
| 1065 | route->control, route->source); | ||
| 1066 | if (ret < 0) { | ||
| 1067 | printk(KERN_ERR "Failed to add route %s->%s\n", | ||
| 1068 | route->source, | ||
| 1069 | route->sink); | ||
| 1070 | return ret; | ||
| 1071 | } | ||
| 1072 | route++; | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | return 0; | ||
| 1076 | } | ||
| 1077 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); | ||
| 1078 | |||
| 1079 | /** | ||
| 963 | * snd_soc_dapm_new_widgets - add new dapm widgets | 1080 | * snd_soc_dapm_new_widgets - add new dapm widgets |
| 964 | * @codec: audio codec | 1081 | * @codec: audio codec |
| 965 | * | 1082 | * |
| @@ -1234,6 +1351,33 @@ int snd_soc_dapm_new_control(struct snd_soc_codec *codec, | |||
| 1234 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | 1351 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); |
| 1235 | 1352 | ||
| 1236 | /** | 1353 | /** |
| 1354 | * snd_soc_dapm_new_controls - create new dapm controls | ||
| 1355 | * @codec: audio codec | ||
| 1356 | * @widget: widget array | ||
| 1357 | * @num: number of widgets | ||
| 1358 | * | ||
| 1359 | * Creates new DAPM controls based upon the templates. | ||
| 1360 | * | ||
| 1361 | * Returns 0 for success else error. | ||
| 1362 | */ | ||
| 1363 | int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, | ||
| 1364 | const struct snd_soc_dapm_widget *widget, | ||
| 1365 | int num) | ||
| 1366 | { | ||
| 1367 | int i, ret; | ||
| 1368 | |||
| 1369 | for (i = 0; i < num; i++) { | ||
| 1370 | ret = snd_soc_dapm_new_control(codec, widget); | ||
| 1371 | if (ret < 0) | ||
| 1372 | return ret; | ||
| 1373 | widget++; | ||
| 1374 | } | ||
| 1375 | return 0; | ||
| 1376 | } | ||
| 1377 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); | ||
| 1378 | |||
| 1379 | |||
| 1380 | /** | ||
| 1237 | * snd_soc_dapm_stream_event - send a stream event to the dapm core | 1381 | * snd_soc_dapm_stream_event - send a stream event to the dapm core |
| 1238 | * @codec: audio codec | 1382 | * @codec: audio codec |
| 1239 | * @stream: stream name | 1383 | * @stream: stream name |
| @@ -1257,8 +1401,8 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
| 1257 | { | 1401 | { |
| 1258 | if (!w->sname) | 1402 | if (!w->sname) |
| 1259 | continue; | 1403 | continue; |
| 1260 | dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname, | 1404 | pr_debug("widget %s\n %s stream %s event %d\n", |
| 1261 | stream, event); | 1405 | w->name, w->sname, stream, event); |
| 1262 | if (strstr(w->sname, stream)) { | 1406 | if (strstr(w->sname, stream)) { |
| 1263 | switch(event) { | 1407 | switch(event) { |
| 1264 | case SND_SOC_DAPM_STREAM_START: | 1408 | case SND_SOC_DAPM_STREAM_START: |
| @@ -1294,53 +1438,81 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
| 1294 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | 1438 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); |
| 1295 | 1439 | ||
| 1296 | /** | 1440 | /** |
| 1297 | * snd_soc_dapm_device_event - send a device event to the dapm core | 1441 | * snd_soc_dapm_set_bias_level - set the bias level for the system |
| 1298 | * @socdev: audio device | 1442 | * @socdev: audio device |
| 1299 | * @event: device event | 1443 | * @level: level to configure |
| 1300 | * | 1444 | * |
| 1301 | * Sends a device event to the dapm core. The core then makes any | 1445 | * Configure the bias (power) levels for the SoC audio device. |
| 1302 | * necessary machine or codec power changes.. | ||
| 1303 | * | 1446 | * |
| 1304 | * Returns 0 for success else error. | 1447 | * Returns 0 for success else error. |
| 1305 | */ | 1448 | */ |
| 1306 | int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event) | 1449 | int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, |
| 1450 | enum snd_soc_bias_level level) | ||
| 1307 | { | 1451 | { |
| 1308 | struct snd_soc_codec *codec = socdev->codec; | 1452 | struct snd_soc_codec *codec = socdev->codec; |
| 1309 | struct snd_soc_machine *machine = socdev->machine; | 1453 | struct snd_soc_machine *machine = socdev->machine; |
| 1454 | int ret = 0; | ||
| 1310 | 1455 | ||
| 1311 | if (machine->dapm_event) | 1456 | if (machine->set_bias_level) |
| 1312 | machine->dapm_event(machine, event); | 1457 | ret = machine->set_bias_level(machine, level); |
| 1313 | if (codec->dapm_event) | 1458 | if (ret == 0 && codec->set_bias_level) |
| 1314 | codec->dapm_event(codec, event); | 1459 | ret = codec->set_bias_level(codec, level); |
| 1315 | return 0; | 1460 | |
| 1461 | return ret; | ||
| 1316 | } | 1462 | } |
| 1317 | EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event); | ||
| 1318 | 1463 | ||
| 1319 | /** | 1464 | /** |
| 1320 | * snd_soc_dapm_set_endpoint - set audio endpoint status | 1465 | * snd_soc_dapm_enable_pin - enable pin. |
| 1466 | * @snd_soc_codec: SoC codec | ||
| 1467 | * @pin: pin name | ||
| 1468 | * | ||
| 1469 | * Enables input/output pin and it's parents or children widgets iff there is | ||
| 1470 | * a valid audio route and active audio stream. | ||
| 1471 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
| 1472 | * do any widget power switching. | ||
| 1473 | */ | ||
| 1474 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin) | ||
| 1475 | { | ||
| 1476 | return snd_soc_dapm_set_pin(codec, pin, 1); | ||
| 1477 | } | ||
| 1478 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | ||
| 1479 | |||
| 1480 | /** | ||
| 1481 | * snd_soc_dapm_disable_pin - disable pin. | ||
| 1482 | * @codec: SoC codec | ||
| 1483 | * @pin: pin name | ||
| 1484 | * | ||
| 1485 | * Disables input/output pin and it's parents or children widgets. | ||
| 1486 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
| 1487 | * do any widget power switching. | ||
| 1488 | */ | ||
| 1489 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin) | ||
| 1490 | { | ||
| 1491 | return snd_soc_dapm_set_pin(codec, pin, 0); | ||
| 1492 | } | ||
| 1493 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | ||
| 1494 | |||
| 1495 | /** | ||
| 1496 | * snd_soc_dapm_get_pin_status - get audio pin status | ||
| 1321 | * @codec: audio codec | 1497 | * @codec: audio codec |
| 1322 | * @endpoint: audio signal endpoint (or start point) | 1498 | * @pin: audio signal pin endpoint (or start point) |
| 1323 | * @status: point status | ||
| 1324 | * | 1499 | * |
| 1325 | * Set audio endpoint status - connected or disconnected. | 1500 | * Get audio pin status - connected or disconnected. |
| 1326 | * | 1501 | * |
| 1327 | * Returns 0 for success else error. | 1502 | * Returns 1 for connected otherwise 0. |
| 1328 | */ | 1503 | */ |
| 1329 | int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, | 1504 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin) |
| 1330 | char *endpoint, int status) | ||
| 1331 | { | 1505 | { |
| 1332 | struct snd_soc_dapm_widget *w; | 1506 | struct snd_soc_dapm_widget *w; |
| 1333 | 1507 | ||
| 1334 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 1508 | list_for_each_entry(w, &codec->dapm_widgets, list) { |
| 1335 | if (!strcmp(w->name, endpoint)) { | 1509 | if (!strcmp(w->name, pin)) |
| 1336 | w->connected = status; | 1510 | return w->connected; |
| 1337 | return 0; | ||
| 1338 | } | ||
| 1339 | } | 1511 | } |
| 1340 | 1512 | ||
| 1341 | return -ENODEV; | 1513 | return 0; |
| 1342 | } | 1514 | } |
| 1343 | EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint); | 1515 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); |
| 1344 | 1516 | ||
| 1345 | /** | 1517 | /** |
| 1346 | * snd_soc_dapm_free - free dapm resources | 1518 | * snd_soc_dapm_free - free dapm resources |
diff --git a/sound/sparc/Kconfig b/sound/sparc/Kconfig index 079e22af074c..d75deba5617d 100644 --- a/sound/sparc/Kconfig +++ b/sound/sparc/Kconfig | |||
| @@ -1,11 +1,17 @@ | |||
| 1 | # ALSA Sparc drivers | 1 | # ALSA Sparc drivers |
| 2 | 2 | ||
| 3 | menu "ALSA Sparc devices" | 3 | menuconfig SND_SPARC |
| 4 | depends on SND!=n && SPARC | 4 | bool "Sparc sound devices" |
| 5 | depends on SPARC | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices specific to Sun SPARC architectures. | ||
| 9 | |||
| 10 | if SND_SPARC | ||
| 5 | 11 | ||
| 6 | config SND_SUN_AMD7930 | 12 | config SND_SUN_AMD7930 |
| 7 | tristate "Sun AMD7930" | 13 | tristate "Sun AMD7930" |
| 8 | depends on SBUS && SND | 14 | depends on SBUS |
| 9 | select SND_PCM | 15 | select SND_PCM |
| 10 | help | 16 | help |
| 11 | Say Y here to include support for AMD7930 sound device on Sun. | 17 | Say Y here to include support for AMD7930 sound device on Sun. |
| @@ -15,7 +21,6 @@ config SND_SUN_AMD7930 | |||
| 15 | 21 | ||
| 16 | config SND_SUN_CS4231 | 22 | config SND_SUN_CS4231 |
| 17 | tristate "Sun CS4231" | 23 | tristate "Sun CS4231" |
| 18 | depends on SND | ||
| 19 | select SND_PCM | 24 | select SND_PCM |
| 20 | help | 25 | help |
| 21 | Say Y here to include support for CS4231 sound device on Sun. | 26 | Say Y here to include support for CS4231 sound device on Sun. |
| @@ -25,7 +30,7 @@ config SND_SUN_CS4231 | |||
| 25 | 30 | ||
| 26 | config SND_SUN_DBRI | 31 | config SND_SUN_DBRI |
| 27 | tristate "Sun DBRI" | 32 | tristate "Sun DBRI" |
| 28 | depends on SND && SBUS | 33 | depends on SBUS |
| 29 | select SND_PCM | 34 | select SND_PCM |
| 30 | help | 35 | help |
| 31 | Say Y here to include support for DBRI sound device on Sun. | 36 | Say Y here to include support for DBRI sound device on Sun. |
| @@ -33,4 +38,4 @@ config SND_SUN_DBRI | |||
| 33 | To compile this driver as a module, choose M here: the module | 38 | To compile this driver as a module, choose M here: the module |
| 34 | will be called snd-sun-dbri. | 39 | will be called snd-sun-dbri. |
| 35 | 40 | ||
| 36 | endmenu | 41 | endif # SND_SPARC |
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 3d00e0797b11..ee2e1b4f3551 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
| @@ -2490,7 +2490,7 @@ static void dbri_debug_read(struct snd_info_entry *entry, | |||
| 2490 | } | 2490 | } |
| 2491 | #endif | 2491 | #endif |
| 2492 | 2492 | ||
| 2493 | void __devinit snd_dbri_proc(struct snd_card *card) | 2493 | static void __devinit snd_dbri_proc(struct snd_card *card) |
| 2494 | { | 2494 | { |
| 2495 | struct snd_dbri *dbri = card->private_data; | 2495 | struct snd_dbri *dbri = card->private_data; |
| 2496 | struct snd_info_entry *entry; | 2496 | struct snd_info_entry *entry; |
diff --git a/sound/spi/Kconfig b/sound/spi/Kconfig index 0d08c29213c8..e6485be2e6f7 100644 --- a/sound/spi/Kconfig +++ b/sound/spi/Kconfig | |||
| @@ -1,7 +1,13 @@ | |||
| 1 | #SPI drivers | 1 | #SPI drivers |
| 2 | 2 | ||
| 3 | menu "SPI devices" | 3 | menuconfig SND_SPI |
| 4 | depends on SND != n | 4 | bool "SPI sound devices" |
| 5 | depends on SPI | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices connected via the SPI bus. | ||
| 9 | |||
| 10 | if SND_SPI | ||
| 5 | 11 | ||
| 6 | config SND_AT73C213 | 12 | config SND_AT73C213 |
| 7 | tristate "Atmel AT73C213 DAC driver" | 13 | tristate "Atmel AT73C213 DAC driver" |
| @@ -28,4 +34,5 @@ config SND_AT73C213_TARGET_BITRATE | |||
| 28 | 34 | ||
| 29 | Set to 48000 Hz by default. | 35 | Set to 48000 Hz by default. |
| 30 | 36 | ||
| 31 | endmenu | 37 | endif # SND_SPI |
| 38 | |||
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 9351b8a765b9..ffcdc8f4ef66 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
| @@ -1,11 +1,16 @@ | |||
| 1 | # ALSA USB drivers | 1 | # ALSA USB drivers |
| 2 | 2 | ||
| 3 | menu "USB devices" | 3 | menuconfig SND_USB |
| 4 | depends on SND!=n && USB!=n | 4 | bool "USB sound devices" |
| 5 | depends on USB | ||
| 6 | default y | ||
| 7 | help | ||
| 8 | Support for sound devices connected via the USB bus. | ||
| 9 | |||
| 10 | if SND_USB && USB | ||
| 5 | 11 | ||
| 6 | config SND_USB_AUDIO | 12 | config SND_USB_AUDIO |
| 7 | tristate "USB Audio/MIDI driver" | 13 | tristate "USB Audio/MIDI driver" |
| 8 | depends on SND && USB | ||
| 9 | select SND_HWDEP | 14 | select SND_HWDEP |
| 10 | select SND_RAWMIDI | 15 | select SND_RAWMIDI |
| 11 | select SND_PCM | 16 | select SND_PCM |
| @@ -18,7 +23,7 @@ config SND_USB_AUDIO | |||
| 18 | 23 | ||
| 19 | config SND_USB_USX2Y | 24 | config SND_USB_USX2Y |
| 20 | tristate "Tascam US-122, US-224 and US-428 USB driver" | 25 | tristate "Tascam US-122, US-224 and US-428 USB driver" |
| 21 | depends on SND && USB && (X86 || PPC || ALPHA) | 26 | depends on X86 || PPC || ALPHA |
| 22 | select SND_HWDEP | 27 | select SND_HWDEP |
| 23 | select SND_RAWMIDI | 28 | select SND_RAWMIDI |
| 24 | select SND_PCM | 29 | select SND_PCM |
| @@ -31,7 +36,6 @@ config SND_USB_USX2Y | |||
| 31 | 36 | ||
| 32 | config SND_USB_CAIAQ | 37 | config SND_USB_CAIAQ |
| 33 | tristate "Native Instruments USB audio devices" | 38 | tristate "Native Instruments USB audio devices" |
| 34 | depends on SND && USB | ||
| 35 | select SND_HWDEP | 39 | select SND_HWDEP |
| 36 | select SND_RAWMIDI | 40 | select SND_RAWMIDI |
| 37 | select SND_PCM | 41 | select SND_PCM |
| @@ -63,5 +67,5 @@ config SND_USB_CAIAQ_INPUT | |||
| 63 | * Native Instruments Kore Controller 2 | 67 | * Native Instruments Kore Controller 2 |
| 64 | * Native Instruments Audio Kontrol 1 | 68 | * Native Instruments Audio Kontrol 1 |
| 65 | 69 | ||
| 66 | endmenu | 70 | endif # SND_USB |
| 67 | 71 | ||
diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c index 24970a5c888f..b3a603325835 100644 --- a/sound/usb/caiaq/caiaq-audio.c +++ b/sound/usb/caiaq/caiaq-audio.c | |||
| @@ -637,6 +637,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) | |||
| 637 | switch (dev->chip.usb_id) { | 637 | switch (dev->chip.usb_id) { |
| 638 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | 638 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): |
| 639 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 639 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
| 640 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO): | ||
| 640 | dev->samplerates |= SNDRV_PCM_RATE_88200; | 641 | dev->samplerates |= SNDRV_PCM_RATE_88200; |
| 641 | dev->samplerates |= SNDRV_PCM_RATE_192000; | 642 | dev->samplerates |= SNDRV_PCM_RATE_192000; |
| 642 | break; | 643 | break; |
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index a972f77bd785..83175083e50f 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c | |||
| @@ -42,14 +42,15 @@ | |||
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 44 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); |
| 45 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.6"); | 45 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8"); |
| 46 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL"); |
| 47 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | 47 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," |
| 48 | "{Native Instruments, RigKontrol3}," | 48 | "{Native Instruments, RigKontrol3}," |
| 49 | "{Native Instruments, Kore Controller}," | 49 | "{Native Instruments, Kore Controller}," |
| 50 | "{Native Instruments, Kore Controller 2}," | 50 | "{Native Instruments, Kore Controller 2}," |
| 51 | "{Native Instruments, Audio Kontrol 1}" | 51 | "{Native Instruments, Audio Kontrol 1}," |
| 52 | "{Native Instruments, Audio 8 DJ}}"); | 52 | "{Native Instruments, Audio 8 DJ}," |
| 53 | "{Native Instruments, Session I/O}}"); | ||
| 53 | 54 | ||
| 54 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | 55 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ |
| 55 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ | 56 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ |
| @@ -110,6 +111,11 @@ static struct usb_device_id snd_usb_id_table[] = { | |||
| 110 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | 111 | .idVendor = USB_VID_NATIVEINSTRUMENTS, |
| 111 | .idProduct = USB_PID_AUDIO8DJ | 112 | .idProduct = USB_PID_AUDIO8DJ |
| 112 | }, | 113 | }, |
| 114 | { | ||
| 115 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
| 116 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | ||
| 117 | .idProduct = USB_PID_SESSIONIO | ||
| 118 | }, | ||
| 113 | { /* terminator */ } | 119 | { /* terminator */ } |
| 114 | }; | 120 | }; |
| 115 | 121 | ||
diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index 96a491379c60..f9fbdbae269d 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #define USB_PID_KORECONTROLLER2 0x4712 | 11 | #define USB_PID_KORECONTROLLER2 0x4712 |
| 12 | #define USB_PID_AK1 0x0815 | 12 | #define USB_PID_AK1 0x0815 |
| 13 | #define USB_PID_AUDIO8DJ 0x1978 | 13 | #define USB_PID_AUDIO8DJ 0x1978 |
| 14 | #define USB_PID_SESSIONIO 0x1915 | ||
| 14 | 15 | ||
| 15 | #define EP1_BUFSIZE 64 | 16 | #define EP1_BUFSIZE 64 |
| 16 | #define CAIAQ_USB_STR_LEN 0xff | 17 | #define CAIAQ_USB_STR_LEN 0xff |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 410be4aff1ba..b8cfb7c22768 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
| @@ -819,10 +819,6 @@ static const char *usb_error_string(int err) | |||
| 819 | return "device disabled"; | 819 | return "device disabled"; |
| 820 | case -EHOSTUNREACH: | 820 | case -EHOSTUNREACH: |
| 821 | return "device suspended"; | 821 | return "device suspended"; |
| 822 | #ifndef CONFIG_USB_EHCI_SPLIT_ISO | ||
| 823 | case -ENOSYS: | ||
| 824 | return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub"; | ||
| 825 | #endif | ||
| 826 | case -EINVAL: | 822 | case -EINVAL: |
| 827 | case -EAGAIN: | 823 | case -EAGAIN: |
| 828 | case -EFBIG: | 824 | case -EFBIG: |
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 82a8d14c26af..9ea726c049c6 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
| @@ -210,6 +210,11 @@ YAMAHA_DEVICE(0x1042, NULL), | |||
| 210 | YAMAHA_DEVICE(0x1043, NULL), | 210 | YAMAHA_DEVICE(0x1043, NULL), |
| 211 | YAMAHA_DEVICE(0x1044, NULL), | 211 | YAMAHA_DEVICE(0x1044, NULL), |
| 212 | YAMAHA_DEVICE(0x1045, NULL), | 212 | YAMAHA_DEVICE(0x1045, NULL), |
| 213 | YAMAHA_INTERFACE(0x104e, 0, NULL), | ||
| 214 | YAMAHA_DEVICE(0x104f, NULL), | ||
| 215 | YAMAHA_DEVICE(0x1050, NULL), | ||
| 216 | YAMAHA_DEVICE(0x1051, NULL), | ||
| 217 | YAMAHA_DEVICE(0x1052, NULL), | ||
| 213 | YAMAHA_DEVICE(0x2000, "DGP-7"), | 218 | YAMAHA_DEVICE(0x2000, "DGP-7"), |
| 214 | YAMAHA_DEVICE(0x2001, "DGP-5"), | 219 | YAMAHA_DEVICE(0x2001, "DGP-5"), |
| 215 | YAMAHA_DEVICE(0x2002, NULL), | 220 | YAMAHA_DEVICE(0x2002, NULL), |
| @@ -1379,6 +1384,39 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1379 | } | 1384 | } |
| 1380 | }, | 1385 | }, |
| 1381 | 1386 | ||
| 1387 | { | ||
| 1388 | /* Roland SonicCell */ | ||
| 1389 | USB_DEVICE(0x0582, 0x00c2), | ||
| 1390 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 1391 | .vendor_name = "Roland", | ||
| 1392 | .product_name = "SonicCell", | ||
| 1393 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 1394 | .type = QUIRK_COMPOSITE, | ||
| 1395 | .data = (const struct snd_usb_audio_quirk[]) { | ||
| 1396 | { | ||
| 1397 | .ifnum = 0, | ||
| 1398 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 1399 | }, | ||
| 1400 | { | ||
| 1401 | .ifnum = 1, | ||
| 1402 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
| 1403 | }, | ||
| 1404 | { | ||
| 1405 | .ifnum = 2, | ||
| 1406 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
| 1407 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
| 1408 | .out_cables = 0x0001, | ||
| 1409 | .in_cables = 0x0001 | ||
| 1410 | } | ||
| 1411 | }, | ||
| 1412 | { | ||
| 1413 | .ifnum = -1 | ||
| 1414 | } | ||
| 1415 | } | ||
| 1416 | } | ||
| 1417 | }, | ||
| 1418 | |||
| 1419 | |||
| 1382 | /* Guillemot devices */ | 1420 | /* Guillemot devices */ |
| 1383 | { | 1421 | { |
| 1384 | /* | 1422 | /* |
