diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-12-10 16:20:14 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-12-10 16:20:14 +1100 |
commit | c4f764d8782dc4591068827d332f386eb95ce078 (patch) | |
tree | e45c6091f0dfe4ffd85346bf6b0cdb5aedec0fc7 | |
parent | 95e22584496e9e6eb1628ffc5d7448f1d45090f7 (diff) |
Revert "Merge commit 'sound/for-next'"
This reverts commit f55a178f9de332704d5c386b7403f006fde8646e.
229 files changed, 7077 insertions, 19023 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 83d3a562fe86..3cd2ad958176 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -778,8 +778,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. specify a certain model in such a case. There are different models depending on the codec chip. - See Documentation/sound/alsa/HD-Audio.txt for some details. - Model name Description ---------- ----------- ALC880 @@ -846,7 +844,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 3stack 3-stack model toshiba Toshiba A205 acer Acer laptops - acer-dmic Acer laptops with digital-mic acer-aspire Acer Aspire One dell Dell OEM laptops (Vostro 1200) zepto Zepto laptops @@ -860,8 +857,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. quanta Quanta FL1 eeepc-p703 ASUS Eeepc P703 P900A eeepc-p901 ASUS Eeepc P901 S101 - fujitsu FSC Amilo - auto auto-config reading BIOS (default) ALC662/663 3stack-dig 3-stack (2-channel) with SPDIF @@ -905,7 +900,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack-dig-demo 6-jack digital for Intel demo board acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) acer-aspire Acer Aspire 9810 - acer-aspire-4930g Acer Aspire 4930G medion Medion Laptops medion-md2 Medion MD2 targa-dig Targa/MSI @@ -921,7 +915,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. mitac Mitac 8252D clevo-m720 Clevo M720 laptop series fujitsu-pi2515 Fujitsu AMILO Pi2515 - fujitsu-xa3530 Fujitsu AMILO XA3530 3stack-6ch-intel Intel DG33* boards auto auto-config reading BIOS (default) @@ -945,7 +938,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. lenovo Lenovo 3000 C200 dallas Dallas laptops hp HP TX1000 - asus-v1s ASUS V1Sn auto auto-config reading BIOS (default) CMI9880 @@ -987,10 +979,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack 6-jack, separate surrounds (default) 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (ASUS A6J) + laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) ultra 2-channel with EAPD (Samsung Ultra tablet PC) - samsung 2-channel with EAPD (Samsung R65) AD1988/AD1988B/AD1989A/AD1989B 6stack 6-jack @@ -1098,8 +1089,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. "codec-patch". It's sometimes good for testing and debugging. If the default configuration doesn't work and one of the above - matches with your device, report it together with alsa-info.sh - output (with --no-upload option) to kernel bugzilla or alsa-devel + matches with your device, report it together with the PCI + subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel ML (see the section "Links and Addresses"). power_save and power_save_controller options are for power-saving @@ -1659,8 +1650,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * AuzenTech X-Meridian * Bgears b-Enspirer * Club3D Theatron DTS - * HT-Omega Claro (plus) - * HT-Omega Claro halo (XT) + * HT-Omega Claro * Razer Barracuda AC-1 * Sondigo Inferno @@ -2417,11 +2407,8 @@ Links and Addresses ALSA project homepage http://www.alsa-project.org - Kernel Bugzilla - http://bugzilla.kernel.org/ + ALSA Bug Tracking System + https://bugtrack.alsa-project.org/bugs/ ALSA Developers ML mailto:alsa-devel@alsa-project.org - - alsa-info.sh script - http://www.alsa-project.org/alsa-info.sh diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt deleted file mode 100644 index e758f24017bf..000000000000 --- a/Documentation/sound/alsa/HD-Audio.txt +++ /dev/null @@ -1,535 +0,0 @@ -MORE NOTES ON HD-AUDIO DRIVER -============================= - Takashi Iwai <tiwai@suse.de> - - -GENERAL -------- - -HD-audio is the new standard on-board audio component on modern PCs -after AC97. Although Linux has been supporting HD-audio since long -time ago, there are often problems with new machines. A part of the -problem is broken BIOS, and rest is the driver implementation. This -document explains the trouble-shooting and debugging methods for the -HD-audio hardware. - -The HD-audio component consists of two parts: the controller chip and -the codec chips on the HD-audio bus. Linux provides a single driver -for all controllers, snd-hda-intel. Since the HD-audio controllers -are supposed to be compatible, the single snd-hda-driver should work -in most cases. But, not surprisingly, there are known bugs and issues -specific to each controller type. The snd-hda-intel driver has a -bunch of workarounds for these as described below. - -A controller may have multiple codecs. Usually you have one audio -codec and optionally one modem codec. In some cases, there can be -multiple audio codecs, e.g. for analog and digital outputs, but the -driver might not work properly. - -The snd-hda-intel driver has several different codec parsers depending -on the codec. It has a generic parser as a fallback, but this -functionality is fairly limited until now. Instead of the generic -parser, usually the codec-specific parser (coded in patch_*.c) is used -for the codec-specific implementations. The details about the -codec-specific problems are explained in the later sections. - -If you are interested in the deep debugging of HD-audio, read the -HD-audio specification at first. The specification is found on -Intel's web page, for example: - -- http://www.intel.com/standards/hdaudio/ - - -HD-AUDIO CONTROLLER -------------------- - -DMA-Position Problem -~~~~~~~~~~~~~~~~~~~~ -The most common problem of the controller is the inaccurate DMA -pointer reporting. The DMA pointer for playback and capture can be -read in two ways, either via a LPIB register or via a position-buffer -map. As default the driver tries to reads from the io-mapped -position-buffer, and falls back to LPIB if it appears unupdated. -However, this detection isn't perfect on some devices. In such a -case, you can change the default method via `position_fix` option. - -`position_fix=1` means to use LPIB method explicitly. -`position_fix=2` means to use the position-buffer. 0 is the default -value, the automatic check. If you get a problem of repeated sounds, -this option might help. - -In addition to that, every controller is known to be broken regarding -the wake-up timing. It wakes up a few samples before actually -processing the data on the buffer. This caused a lot of problems, for -example, with ALSA dmix or JACK. Since 2.6.27 kernel, the driver puts -an artificial delay to the wake up timing. This delay is controlled -via `bdl_pos_adj` option. - -When `bdl_pos_adj` is a negative value (as default), it's assigned to -an appropriate value depending on the controller chip. For Intel -chip, it'd be 1 while it'd be 32 for others. Usually this works. -Only in case it doesn't work and you get warning messages, you should -change to other values. - - -Codec-Probing Problem -~~~~~~~~~~~~~~~~~~~~~ -A less often but a more severe problem is the codec probing. When -BIOS reports the available codec slots wrongly, the driver gets -confused and tries to access the non-existing codec slot. This often -results in the total screw-up, and destruct the further communication -with the codec chips. The symptom appears usually as the error -message like: ------------------------------------------------------------------------- - hda_intel: azx_get_response timeout, switching to polling mode: \ - last cmd=0x12345678 - hda_intel: azx_get_response timeout, switching to single_cmd mode: \ - last cmd=0x12345678 ------------------------------------------------------------------------- - -The first line is a warning, and this is usually relatively harmless. -It means that the codec response isn't notified via an IRQ. The -driver uses explicit polling method to read the response. It gives -very slight CPU overhead, but you'd unlikely notice it. - -The second line is, however, a fatal error. If this happens, usually -it means that something is really wrong. Most likely you are -accessing a non-existing codec slot. - -Thus, if the second error message appears, try to narrow the probed -codec slots via `probe_mask` option. It's a bitmask, and each bit -corresponding to the codec slot. For example, to probe only the -first slot, pass `probe_mask=1`. For the first and the third slots, -pass `probe_mask=5` (where 5 = 1 | 4), and so on. - -Since 2.6.29 kernel, the driver has a more robust probing method, so -this error might happen rarely, though. - - -Interrupt Handling -~~~~~~~~~~~~~~~~~~ -In rare but some cases, the interrupt isn't properly handled as -default. You would notice this by the DMA transfer error reported by -ALSA PCM core, for example. Using MSI might help in such a case. -Pass `enable_msi=1` option for enabling MSI. - - -HD-AUDIO CODEC --------------- - -Model Option -~~~~~~~~~~~~ -The most common problems with the HD-audio driver is the unsupported -codec features or the mismatched device configuration. Most of -codec-specific code has several preset models, either to override the -BIOS setup or to provide more comprehensive features. - -The driver checks PCI SSID and looks through the static configuration -table until any matching entry is found. If you have a new machine, -you may see a message like below: ------------------------------------------------------------------------- - hda_codec: Unknown model for ALC880, trying auto-probe from BIOS... ------------------------------------------------------------------------- -Even if you such a message, DON'T PANIC. Take a deep breath (and keep -your towel). First of all, it's an informational message, no warning, -no error. This means that the PCI SSID of your device isn't listed in -the known preset model list. But, this doesn't mean that the driver -is broken. Many codec-driver provides the automatic configuration -based on the BIOS setup. - -The HD-audio codec has usually "pin" widgets, and BIOS sets the default -configuration of each pin, which indicates the location, the -connection type, the jack color, etc. The HD-audio driver can guess -the right connection judging from these default configuration values. -However -- some codec support codes, such as patch_analog.c, don't -support the automatic probing (yet as of 2.6.28). And, BIOS is often, -yes, pretty often broken. It sets up wrong values and screws up the -driver. - -The preset model is provided basically to override such a situation. -When the matching preset model is found in the list, the driver -assumes the static configuration of that preset and builds the mixer -and PCM based on the static information. Thus, if you have a newer -machine with a slightly different PCI SSID from the existing one, you -may have a good chance to re-use the same model. You can pass the -`model` option to specify the preset model instead of PCI SSID -look-up. - -What `model` option values are available depends on the codec chip. -Check your codec chip from the codec proc file (see "Codec Proc-File" -section below). It will show the vendor/product name of your codec -chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt file. -In the section of HD-audio driver, you can find a list of codecs and -`model` options belonging to each codec. For example, for Realtek -ALC262 codec chip, pass `model=ultra` for devices that are compatible -with Samsung Q1 Ultra. - -Thus, the first thing you can do for any brand-new, unsupported -HD-audio hardware is to check HD-audio codec and several different -`model` option values. If you have a luck, some of them might suit -with your device well. - -Some codecs such as ALC880 have a special model option `model=test`. -This configures the driver to provide as many mixer controls as -possible for every single pin feature except for the unsolicited -events (and maybe some other specials). Adjust each mixer element and -try the I/O in the way of trial-and-error until figuring out the whole -I/O pin mappings. - -Note that `model=generic` has a special meaning. It means to use the -generic parser regardless of the codec. Usually the codec-specific -parser is much better than the generic parser (as now). Thus this -option is more about the debugging purpose. - - -Speaker and Headphone Output -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -One of the most frequent (and obvious) bugs with HD-audio is the -silent output from either or both of a built-in speaker and a -headphone jack. In general, you should try a headphone output at -first. A speaker output often requires more additional controls like -the amplifier. Thus a headphone output has a slightly better chance. - -Before making a bug report, double-check whether the mixer is set up -correctly. The recent version of snd-hda-intel driver provides mostly -"Master" volume control as well as "Front" volume. In addition, there -are individual "Headphone" and "Speaker" controls. - -Ditto for the speaker output. There can be "External Amplifier" -switch on some codecs. Turn on this if present. - -Another related problem is the automatic mute of speaker output by -headphone plugging. This feature is implemented in most cases, but -not on every preset model or codec-support code. - -In anyway, try a different model option if you have such a problem. -Some other models may match better and give you more matching -functionality. If none of the available models works, send a bug -report. See the bug report section for details. - -If you are masochistic enough to debug the driver problem, note the -following: - -- The speaker (and the headphone, too) output often requires the - external amplifier. This can be set usually via EAPD verb or a - certain GPIO. If the codec pin supports EAPD, you have a better - chance via SET_EAPD_BTL verb (0x70c). On others, GPIO pin (mostly - it's either GPIO0 or GPIO1) can turn on/off EAPD. -- Some Realtek codecs require special vendor-specific coefficients to - turn on the amplifier. See patch_realtek.c. -- IDT codecs may have extra power-enable/disable controls on each - analog pin. See patch_sigmatel.c. -- Very rare but some devices don't accept the pin-detection verb until - triggered. Issuing GET_PIN_SENSE verb (0xf09) may result in the - codec-communication stall. Some examples are found in - patch_realtek.c. - - -Capture Problems -~~~~~~~~~~~~~~~~ -The capture problems are often missing setups of mixers. Thus, before -submitting a bug report, make sure that you set up the mixer -correctly. For example, both "Capture Volume" and "Capture Switch" -have to be set properly in addition to the right "Capture Source" or -"Input Source" selection. Some devices have "Mic Boost" volume or -switch. - -When the PCM device is opened via "default" PCM (without pulse-audio -plugin), you'll likely have "Digital Capture Volume" control as well. -This is provided for the extra gain/attenuation of the signal in -software, especially for the inputs without the hardware volume -control such as digital microphones. Unless really needed, this -should be set to exactly 50%, corresponding to 0dB. When you use "hw" -PCM, i.e., a raw access PCM, this control will have no influence, -though. - -It's known that some codecs / devices have fairly bad analog circuits, -and the recorded sound contains a certain DC-offset. This is no bug -of the driver. - -Most of modern laptops have no analog CD-input connection. Thus, the -recording from CD input won't work in many cases although the driver -provides it as the capture source. - -The automatic switching of the built-in and external mic per plugging -is implemented on some codec models but not on every model. Partly -because of my laziness but mostly lack of testers. Feel free to -submit the improvement patch to the author. - - -Direct Debugging -~~~~~~~~~~~~~~~~ -If no model option gives you a better result, and you are a touch guy -to fight again the evil, try debugging via hitting the raw HD-audio -codec verbs to the device. Some tools are available: hda-emu and -hda-analyzer. The detailed description is found in the sections -below. You'd need to enable hwdep for using these tools. See "Kernel -Configuration". - - -OTHER ISSUES ------------- - -Kernel Configuration -~~~~~~~~~~~~~~~~~~~~ -In general, I recommend you to enable the sound debug option, -`CONFIG_SND_DEBUG=y`, no matter whether you are debugging or not. -This enables snd_printd() macro and others, and you'll get additional -kernel messages at probing. - -In addition, you can enable `CONFIG_SND_DEBUG_VERBOSE=y`. But this -will give you far more messages. Thus turn this on only when you are -sure to want it. - -Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*` -options. Note that each of them corresponds to the codec chip, not -the controller chip. Thus, even if lspci shows the Nvidia controller, -you may choose the option for other vendors. If you are unsure, just -choose all yes. - -`CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver. -When this is enabled, the driver creates hardware-dependent devices -(one per each codec), and you have a raw access to the device via -hda-verb program. For example, `hwC0D2` will be created for the card -0 codec slot #2. For debug tools such as hda-verb and hda-analyzer, -the hwdep device has to be enabled. Thus, turn this on always. - -`CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the -hwdep option above. When enabled, you'll have some sysfs files under -the corresponding hwdep directory. See "HD-audio reconfiguration" -section below. - -`CONFIG_SND_HDA_POWER_SAVE` option enables the power-saving feature. -See "Power-saving" section below. - - -Codec Proc-File -~~~~~~~~~~~~~~~ -The codec proc-file is a treasure-chest for debugging HD-audio. -It shows most of useful information of each codec widget. - -The proc file is located in /proc/asound/card*/codec#*, one file per -each codec slot. You can know the codec vendor, product id and -names, the type of each widget, capabilities and so on. -This file, however, doesn't show the jack sensing state, so far. This -is because the jack-sensing might be depending on the trigger state. - -This file will be picked up by the debug tools, and also it can be fed -to the emulator as the primary codec information. See the debug tools -section below. - -This proc file can be also used to check whether the generic parser is -used. When the generic parser is used, the vendor/product ID name -will appear as "Realtek ID 0262", instead of "Realtek ALC262". - - -HD-Audio Reconfiguration -~~~~~~~~~~~~~~~~~~~~~~~~ -This is an experimental feature to allow you re-configure the HD-audio -codec dynamically without reloading the driver. The following sysfs -files are available under each codec-hwdep device directory (e.g. -/sys/class/sound/hwC0D0): - -vendor_id:: - Shows the 32bit codec vendor-id hex number. You can change the - vendor-id value by writing to this file. -subsystem_id:: - Shows the 32bit codec subsystem-id hex number. You can change the - subsystem-id value by writing to this file. -revision_id:: - Shows the 32bit codec revision-id hex number. You can change the - revision-id value by writing to this file. -afg:: - Shows the AFG ID. This is read-only. -mfg:: - Shows the MFG ID. This is read-only. -name:: - Shows the codec name string. Can be changed by writing to this - file. -modelname:: - Shows the currently set `model` option. Can be changed by writing - to this file. -init_verbs:: - The extra verbs to execute at initialization. You can add a verb by - writing to this file. Pass tree numbers, nid, verb and parameter. -hints:: - Shows hint strings for codec parsers for any use. Right now it's - not used. -reconfig:: - Triggers the codec re-configuration. When any value is written to - this file, the driver re-initialize and parses the codec tree - again. All the changes done by the sysfs entries above are taken - into account. -clear:: - Resets the codec, removes the mixer elements and PCM stuff of the - specified codec, and clear all init verbs and hints. - - -Power-Saving -~~~~~~~~~~~~ -The power-saving is a kind of auto-suspend of the device. When the -device is inactive for a certain time, the device is automatically -turned off to save the power. The time to go down is specified via -`power_save` module option, and this option can be changed dynamically -via sysfs. - -The power-saving won't work when the analog loopback is enabled on -some codecs. Make sure that you mute all unneeded signal routes when -you want the power-saving. - -The power-saving feature might cause audible click noises at each -power-down/up depending on the device. Some of them might be -solvable, but some are hard, I'm afraid. Some distros such as -openSUSE enables the power-saving feature automatically when the power -cable is unplugged. Thus, if you hear noises, suspect first the -power-saving. See /sys/modules/snd_hda_intel/parameters/power_save to -check the current value. If it's non-zero, the feature is turned on. - - -Sending a Bug Report -~~~~~~~~~~~~~~~~~~~~ -If any model or module options don't work for your device, it's time -to send a bug report to the developers. Give the following in your -bug report: - -- Hardware vendor, product and model names -- Kernel version (and ALSA-driver version if you built externally) -- `alsa-info.sh` output; run with `--no-upload` option. See the - section below about alsa-info - -If it's a regression, at best, send alsa-info outputs of both working -and non-working kernels. This is really helpful because we can -compare the codec registers directly. - -Send a bug report either the followings: - -kernel-bugzilla:: - http://bugme.linux-foundation.org/ -alsa-devel ML:: - alsa-devel@alsa-project.org - - -DEBUG TOOLS ------------ - -This section describes some tools available for debugging HD-audio -problems. - -alsa-info -~~~~~~~~~ -The script `alsa-info.sh` is a very useful tool to gather the audio -device information. You can fetch the latest version from: - -- http://www.alsa-project.org/alsa-info.sh - -Run this script as root, and it will gather the important information -such as the module lists, module parameters, proc file contents -including the codec proc files, mixer outputs and the control -elements. As default, it will store the information onto a web server -on alsa-project.org. But, if you send a bug report, it'd be better to -run with `--no-upload` option, and attach the generated file. - -There are some other useful options. See `--help` option output for -details. - - -hda-verb -~~~~~~~~ -hda-verb is a tiny program that allows you to access the HD-audio -codec directly. It executes a HD-audio codec verb directly. -This program accesses the hwdep device, thus you need to enable the -kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand. - -The hda-verb program takes four arguments: the hwdep device file, the -widget NID, the verb and the parameter. When you access to the codec -on the slot 2 of the card 0, pass /dev/snd/hwC0D2 to the first -argument, typically. (However, the real path name depends on the -system.) - -The second parameter is the widget number-id to access. The third -parameter can be either a hex/digit number or a string corresponding -to a verb. Similarly, the last parameter is the value to write, or -can be a string for the parameter type. - ------------------------------------------------------------------------- - % hda-verb /dev/snd/hwC0D0 0x12 0x701 2 - nid = 0x12, verb = 0x701, param = 0x2 - value = 0x0 - - % hda-verb /dev/snd/hwC0D0 0x0 PARAMETERS VENDOR_ID - nid = 0x0, verb = 0xf00, param = 0x0 - value = 0x10ec0262 - - % hda-verb /dev/snd/hwC0D0 2 set_a 0xb080 - nid = 0x2, verb = 0x300, param = 0xb080 - value = 0x0 ------------------------------------------------------------------------- - -Although you can issue any verbs with this program, the driver state -won't be always updated. For example, the volume values are usually -cached in the driver, and thus changing the widget amp value directly -via hda-verb won't change the mixer value. - -The hda-verb program is found in the ftp directory: - -- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ - -Also a git repository is available: - -- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-verb.git - -See README file in the tarball for more details about hda-verb -program. - - -hda-analyzer -~~~~~~~~~~~~ -hda-analyzer provides a graphical interface to access the raw HD-audio -control, based on pyGTK2 binding. It's a more powerful version of -hda-verb. The program gives you a easy-to-use GUI stuff for showing -the widget information and adjusting the amp values, as well as the -proc-compatible output. - -The hda-analyzer is a part of alsa.git repository in -alsa-project.org: - -- http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer - - -hda-emu -~~~~~~~ -hda-emu is a HD-audio emulator. The main purpose of this program is -to debug an HD-audio codec without the real hardware. Thus, it -doesn't emulate the behavior with the real audio I/O, but it just -dumps the codec register changes and the ALSA-driver internal changes -at probing and operating the HD-audio driver. - -The program requires a codec proc-file to simulate. Get a proc file -for the target codec beforehand, or pick up an example codec from the -codec proc collections in the tarball. Then, run the program with the -proc file, and the hda-emu program will start parsing the codec file -and simulates the HD-audio driver: - ------------------------------------------------------------------------- - % hda-emu codecs/stac9200-dell-d820-laptop - # Parsing.. - hda_codec: Unknown model for STAC9200, using BIOS defaults - hda_codec: pin nid 08 bios pin config 40c003fa - .... ------------------------------------------------------------------------- - -The program gives you only a very dumb command-line interface. You -can get a proc-file dump at the current state, get a list of control -(mixer) elements, set/get the control element value, simulate the PCM -operation, the jack plugging simulation, etc. - -The package is found in: - -- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ - -A git repository is available: - -- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-emu.git - -See README file in the tarball for more details about hda-emu -program. diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index bba2dbb79d81..f738b296440a 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -153,16 +153,6 @@ card*/codec#* Shows the general codec information and the attribute of each widget node. -card*/eld#* - Available for HDMI or DisplayPort interfaces. - Shows ELD(EDID Like Data) info retrieved from the attached HDMI sink, - and describes its audio capabilities and configurations. - - Some ELD fields may be modified by doing `echo name hex_value > eld#*`. - Only do this if you are sure the HDMI sink provided value is wrong. - And if that makes your HDMI audio work, please report to us so that we - can fix it in future kernel releases. - Sequencer Information --------------------- diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index bab7711ce963..f370e7db86af 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -9,7 +9,7 @@ the audio subsystem with the kernel as a platform device and is represented by the following struct:- /* SoC machine */ -struct snd_soc_card { +struct snd_soc_machine { char *name; int (*probe)(struct platform_device *pdev); @@ -67,10 +67,10 @@ static struct snd_soc_dai_link corgi_dai = { .ops = &corgi_ops, }; -struct snd_soc_card then sets up the machine with it's DAIs. e.g. +struct snd_soc_machine then sets up the machine with it's DAIs. e.g. /* corgi audio machine driver */ -static struct snd_soc_card snd_soc_corgi = { +static struct snd_soc_machine snd_soc_machine_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, @@ -90,7 +90,7 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .machine = &snd_soc_corgi, + .machine = &snd_soc_machine_corgi, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, diff --git a/MAINTAINERS b/MAINTAINERS index 6dad667e9fcc..b791a13afec8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4020,7 +4020,7 @@ M: tiwai@suse.de L: alsa-devel@alsa-project.org (subscribers-only) S: Maintained -SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC) +SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT P: Liam Girdwood M: lrg@slimlogic.co.uk P: Mark Brown diff --git a/arch/arm/mach-pxa/include/mach/palmasoc.h b/arch/arm/mach-pxa/include/mach/palmasoc.h deleted file mode 100644 index 6c4b1f7de20a..000000000000 --- a/arch/arm/mach-pxa/include/mach/palmasoc.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _INCLUDE_PALMASOC_H_ -#define _INCLUDE_PALMASOC_H_ -struct palm27x_asoc_info { - int jack_gpio; -}; - -#ifdef CONFIG_SND_PXA2XX_SOC_PALM27X -void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data); -#else -static inline void palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) {} -#endif - -#endif diff --git a/include/linux/input.h b/include/linux/input.h index 1a958cd90ce9..5341e8251f8c 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -659,7 +659,6 @@ struct input_absinfo { #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ -#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) diff --git a/include/sound/asound.h b/include/sound/asound.h index 1c02ed1d7c4a..2c4dc908a54a 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -575,7 +575,6 @@ enum { #define SNDRV_TIMER_GLOBAL_SYSTEM 0 #define SNDRV_TIMER_GLOBAL_RTC 1 #define SNDRV_TIMER_GLOBAL_HPET 2 -#define SNDRV_TIMER_GLOBAL_HRTIMER 3 /* info flags */ #define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */ diff --git a/include/sound/core.h b/include/sound/core.h index f632484bc743..1508c4ec1ba9 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -353,7 +353,7 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) * snd_printk - printk wrapper * @fmt: format string * - * Works like printk() but prints the file and the line of the caller + * Works like print() but prints the file and the line of the caller * when configured with CONFIG_SND_VERBOSE_PRINTK. */ #define snd_printk(fmt, args...) \ @@ -380,40 +380,18 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) printk(fmt ,##args) #endif -/** - * snd_BUG - give a BUG warning message and stack trace - * - * Calls WARN() if CONFIG_SND_DEBUG is set. - * Ignored when CONFIG_SND_DEBUG is not set. - */ #define snd_BUG() WARN(1, "BUG?\n") - -/** - * snd_BUG_ON - debugging check macro - * @cond: condition to evaluate - * - * When CONFIG_SND_DEBUG is set, this macro evaluates the given condition, - * and call WARN() and returns the value if it's non-zero. - * - * When CONFIG_SND_DEBUG is not set, this just returns zero, and the given - * condition is ignored. - * - * NOTE: the argument won't be evaluated at all when CONFIG_SND_DEBUG=n. - * Thus, don't put any statement that influences on the code behavior, - * such as pre/post increment, to the argument of this macro. - * If you want to evaluate and give a warning, use standard WARN_ON(). - */ #define snd_BUG_ON(cond) WARN((cond), "BUG? (%s)\n", __stringify(cond)) #else /* !CONFIG_SND_DEBUG */ #define snd_printd(fmt, args...) do { } while (0) #define snd_BUG() do { } while (0) -static inline int __snd_bug_on(int cond) +static inline int __snd_bug_on(void) { return 0; } -#define snd_BUG_ON(cond) __snd_bug_on(0 && (cond)) /* always false */ +#define snd_BUG_ON(cond) __snd_bug_on() /* always false */ #endif /* CONFIG_SND_DEBUG */ diff --git a/include/sound/info.h b/include/sound/info.h index 7c2ee1a21b00..8ae72e74f898 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -40,34 +40,30 @@ struct snd_info_buffer { struct snd_info_entry; struct snd_info_entry_text { - void (*read)(struct snd_info_entry *entry, - struct snd_info_buffer *buffer); - void (*write)(struct snd_info_entry *entry, - struct snd_info_buffer *buffer); + void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); + void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); }; struct snd_info_entry_ops { - int (*open)(struct snd_info_entry *entry, - unsigned short mode, void **file_private_data); - int (*release)(struct snd_info_entry *entry, - unsigned short mode, void *file_private_data); - long (*read)(struct snd_info_entry *entry, void *file_private_data, - struct file *file, char __user *buf, - unsigned long count, unsigned long pos); - long (*write)(struct snd_info_entry *entry, void *file_private_data, - struct file *file, const char __user *buf, + int (*open) (struct snd_info_entry *entry, + unsigned short mode, void **file_private_data); + int (*release) (struct snd_info_entry * entry, + unsigned short mode, void *file_private_data); + long (*read) (struct snd_info_entry *entry, void *file_private_data, + struct file * file, char __user *buf, unsigned long count, unsigned long pos); - long long (*llseek)(struct snd_info_entry *entry, - void *file_private_data, struct file *file, - long long offset, int orig); - unsigned int(*poll)(struct snd_info_entry *entry, - void *file_private_data, struct file *file, - poll_table *wait); - int (*ioctl)(struct snd_info_entry *entry, void *file_private_data, - struct file *file, unsigned int cmd, unsigned long arg); - int (*mmap)(struct snd_info_entry *entry, void *file_private_data, - struct inode *inode, struct file *file, - struct vm_area_struct *vma); + long (*write) (struct snd_info_entry *entry, void *file_private_data, + struct file * file, const char __user *buf, + unsigned long count, unsigned long pos); + long long (*llseek) (struct snd_info_entry *entry, void *file_private_data, + struct file * file, long long offset, int orig); + unsigned int (*poll) (struct snd_info_entry *entry, void *file_private_data, + struct file * file, poll_table * wait); + int (*ioctl) (struct snd_info_entry *entry, void *file_private_data, + struct file * file, unsigned int cmd, unsigned long arg); + int (*mmap) (struct snd_info_entry *entry, void *file_private_data, + struct inode * inode, struct file * file, + struct vm_area_struct * vma); }; struct snd_info_entry { @@ -110,37 +106,34 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer); static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {} #endif -int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) \ - __attribute__ ((format (printf, 2, 3))); +int snd_iprintf(struct snd_info_buffer * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3))); int snd_info_init(void); int snd_info_done(void); -int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len); +int snd_info_get_line(struct snd_info_buffer * buffer, char *line, int len); char *snd_info_get_str(char *dest, char *src, int len); -struct snd_info_entry *snd_info_create_module_entry(struct module *module, +struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, - struct snd_info_entry *parent); -struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, + struct snd_info_entry * parent); +struct snd_info_entry *snd_info_create_card_entry(struct snd_card * card, const char *name, - struct snd_info_entry *parent); -void snd_info_free_entry(struct snd_info_entry *entry); -int snd_info_store_text(struct snd_info_entry *entry); -int snd_info_restore_text(struct snd_info_entry *entry); - -int snd_info_card_create(struct snd_card *card); -int snd_info_card_register(struct snd_card *card); -int snd_info_card_free(struct snd_card *card); -void snd_info_card_disconnect(struct snd_card *card); -void snd_info_card_id_change(struct snd_card *card); -int snd_info_register(struct snd_info_entry *entry); + struct snd_info_entry * parent); +void snd_info_free_entry(struct snd_info_entry * entry); +int snd_info_store_text(struct snd_info_entry * entry); +int snd_info_restore_text(struct snd_info_entry * entry); + +int snd_info_card_create(struct snd_card * card); +int snd_info_card_register(struct snd_card * card); +int snd_info_card_free(struct snd_card * card); +void snd_info_card_disconnect(struct snd_card * card); +int snd_info_register(struct snd_info_entry * entry); /* for card drivers */ -int snd_card_proc_new(struct snd_card *card, const char *name, - struct snd_info_entry **entryp); +int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp); static inline void snd_info_set_text_ops(struct snd_info_entry *entry, - void *private_data, - void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) + void *private_data, + void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) { entry->private_data = private_data; entry->c.text.read = read; @@ -153,22 +146,21 @@ int snd_info_check_reserved_words(const char *str); #define snd_seq_root NULL #define snd_oss_root NULL -static inline int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) { return 0; } +static inline int snd_iprintf(struct snd_info_buffer * buffer, char *fmt,...) { return 0; } static inline int snd_info_init(void) { return 0; } static inline int snd_info_done(void) { return 0; } -static inline int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) { return 0; } +static inline int snd_info_get_line(struct snd_info_buffer * buffer, char *line, int len) { return 0; } static inline char *snd_info_get_str(char *dest, char *src, int len) { return NULL; } -static inline struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, struct snd_info_entry *parent) { return NULL; } -static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent) { return NULL; } -static inline void snd_info_free_entry(struct snd_info_entry *entry) { ; } - -static inline int snd_info_card_create(struct snd_card *card) { return 0; } -static inline int snd_info_card_register(struct snd_card *card) { return 0; } -static inline int snd_info_card_free(struct snd_card *card) { return 0; } -static inline void snd_info_card_disconnect(struct snd_card *card) { } -static inline void snd_info_card_id_change(struct snd_card *card) { } -static inline int snd_info_register(struct snd_info_entry *entry) { return 0; } +static inline struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry * parent) { return NULL; } +static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card * card, const char *name, struct snd_info_entry * parent) { return NULL; } +static inline void snd_info_free_entry(struct snd_info_entry * entry) { ; } + +static inline int snd_info_card_create(struct snd_card * card) { return 0; } +static inline int snd_info_card_register(struct snd_card * card) { return 0; } +static inline int snd_info_card_free(struct snd_card * card) { return 0; } +static inline void snd_info_card_disconnect(struct snd_card * card) { } +static inline int snd_info_register(struct snd_info_entry * entry) { return 0; } static inline int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp) { return -EINVAL; } diff --git a/include/sound/jack.h b/include/sound/jack.h index 7cb25f4b50bb..b1b2b8b59adb 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -35,7 +35,6 @@ enum snd_jack_types { SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, - SND_JACK_LINEOUT = 0x0004, }; struct snd_jack { diff --git a/include/sound/l3.h b/include/sound/l3.h deleted file mode 100644 index 423a08f0f1b0..000000000000 --- a/include/sound/l3.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _L3_H_ -#define _L3_H_ 1 - -struct l3_pins { - void (*setdat)(int); - void (*setclk)(int); - void (*setmode)(int); - int data_hold; - int data_setup; - int clock_high; - int mode_hold; - int mode; - int mode_setup; -}; - -int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len); - -#endif diff --git a/include/sound/s3c24xx_uda134x.h b/include/sound/s3c24xx_uda134x.h deleted file mode 100644 index 33df4cb909d3..000000000000 --- a/include/sound/s3c24xx_uda134x.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _S3C24XX_UDA134X_H_ -#define _S3C24XX_UDA134X_H_ 1 - -#include <sound/uda134x.h> - -struct s3c24xx_uda134x_platform_data { - int l3_clk; - int l3_mode; - int l3_data; - void (*power) (int); - int model; -}; - -#endif diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h deleted file mode 100644 index 24247f763608..000000000000 --- a/include/sound/soc-dai.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * linux/sound/soc-dai.h -- ALSA SoC Layer - * - * Copyright: 2005-2008 Wolfson Microelectronics. PLC. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Digital Audio Interface (DAI) API. - */ - -#ifndef __LINUX_SND_SOC_DAI_H -#define __LINUX_SND_SOC_DAI_H - - -#include <linux/list.h> - -struct snd_pcm_substream; - -/* - * DAI hardware audio formats. - * - * Describes the physical PCM data formating and clocking. Add new formats - * to the end. - */ -#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ -#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right Justified mode */ -#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ -#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM LRC */ -#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM LRC */ -#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ - -/* left and right justified also known as MSB and LSB respectively */ -#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J -#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J - -/* - * DAI Clock gating. - * - * DAI bit clocks can be be gated (disabled) when not the DAI is not - * sending or receiving PCM data in a frame. This can be used to save power. - */ -#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ -#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated */ - -/* - * DAI Left/Right Clocks. - * - * Specifies whether the DAI can support different samples for similtanious - * playback and capture. This usually requires a seperate physical frame - * clock for playback and capture. - */ -#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */ -#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */ - -/* - * TDM - * - * Time Division Multiplexing. Allows PCM data to be multplexed with other - * data on the DAI. - */ -#define SND_SOC_DAIFMT_TDM (1 << 6) - -/* - * DAI hardware signal inversions. - * - * Specifies whether the DAI can also support inverted clocks for the specified - * format. - */ -#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ -#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ -#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ -#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ - -/* - * DAI hardware clock masters. - * - * This is wrt the codec, the inverse is true for the interface - * i.e. if the codec is clk and frm master then the interface is - * clk and frame slave. - */ -#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ -#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ -#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ -#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ - -#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f -#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 -#define SND_SOC_DAIFMT_INV_MASK 0x0f00 -#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 - -/* - * Master Clock Directions - */ -#define SND_SOC_CLOCK_IN 0 -#define SND_SOC_CLOCK_OUT 1 - -struct snd_soc_dai_ops; -struct snd_soc_dai; -struct snd_ac97_bus_ops; - -/* Digital Audio Interface registration */ -int snd_soc_register_dai(struct snd_soc_dai *dai); -void snd_soc_unregister_dai(struct snd_soc_dai *dai); -int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count); -void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count); - -/* Digital Audio Interface clocking API.*/ -int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir); - -int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div); - -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out); - -/* Digital Audio interface formatting */ -int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); - -int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots); - -int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); - -/* Digital Audio Interface mute */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); - -/* - * Digital Audio Interface. - * - * Describes the Digital Audio Interface in terms of it's ALSA, DAI and AC97 - * operations an capabilities. Codec and platfom drivers will register a this - * structure for every DAI they have. - * - * This structure covers the clocking, formating and ALSA operations for each - * interface a - */ -struct snd_soc_dai_ops { - /* - * DAI clocking configuration, all optional. - * Called by soc_card drivers, normally in their hw_params. - */ - int (*set_sysclk)(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir); - int (*set_pll)(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out); - int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); - - /* - * DAI format configuration - * Called by soc_card drivers, normally in their hw_params. - */ - int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); - int (*set_tdm_slot)(struct snd_soc_dai *dai, - unsigned int mask, int slots); - int (*set_tristate)(struct snd_soc_dai *dai, int tristate); - - /* - * DAI digital mute - optional. - * Called by soc-core to minimise any pops. - */ - int (*digital_mute)(struct snd_soc_dai *dai, int mute); - - /* - * ALSA PCM audio operations - all optional. - * Called by soc-core during audio PCM operations. - */ - int (*startup)(struct snd_pcm_substream *, - struct snd_soc_dai *); - void (*shutdown)(struct snd_pcm_substream *, - struct snd_soc_dai *); - int (*hw_params)(struct snd_pcm_substream *, - struct snd_pcm_hw_params *, struct snd_soc_dai *); - int (*hw_free)(struct snd_pcm_substream *, - struct snd_soc_dai *); - int (*prepare)(struct snd_pcm_substream *, - struct snd_soc_dai *); - int (*trigger)(struct snd_pcm_substream *, int, - struct snd_soc_dai *); -}; - -/* - * Digital Audio Interface runtime data. - * - * Holds runtime data for a DAI. - */ -struct snd_soc_dai { - /* DAI description */ - char *name; - unsigned int id; - int ac97_control; - - struct device *dev; - - /* DAI callbacks */ - int (*probe)(struct platform_device *pdev, - struct snd_soc_dai *dai); - void (*remove)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*suspend)(struct snd_soc_dai *dai); - int (*resume)(struct snd_soc_dai *dai); - - /* ops */ - struct snd_soc_dai_ops ops; - - /* DAI capabilities */ - struct snd_soc_pcm_stream capture; - struct snd_soc_pcm_stream playback; - - /* DAI runtime info */ - struct snd_pcm_runtime *runtime; - struct snd_soc_codec *codec; - unsigned int active; - unsigned char pop_wait:1; - void *dma_data; - - /* DAI private data */ - void *private_data; - - /* parent codec/platform */ - union { - struct snd_soc_codec *codec; - struct snd_soc_platform *platform; - }; - - struct list_head list; -}; - -#endif diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 7ee2f70ca42e..ca699a3017f3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -221,6 +221,8 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, int num); /* dapm path setup */ +int __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec, + const char *sink_name, const char *control_name, const char *src_name); int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); void snd_soc_dapm_free(struct snd_soc_device *socdev); int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, diff --git a/include/sound/soc.h b/include/sound/soc.h index ce3661d07c24..5e0189876afd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -21,6 +21,8 @@ #include <sound/control.h> #include <sound/ac97_codec.h> +#define SND_SOC_VERSION "0.13.2" + /* * Convenience kcontrol builders */ @@ -143,29 +145,105 @@ enum snd_soc_bias_level { SND_SOC_BIAS_OFF, }; +/* + * Digital Audio Interface (DAI) types + */ +#define SND_SOC_DAI_AC97 0x1 +#define SND_SOC_DAI_I2S 0x2 +#define SND_SOC_DAI_PCM 0x4 +#define SND_SOC_DAI_AC97_BUS 0x8 /* for custom i.e. non ac97_codec.c */ + +/* + * DAI hardware audio formats + */ +#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ +#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */ +#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ +#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */ +#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */ +#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ + +#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J +#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J + +/* + * DAI Gating + */ +#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ +#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */ + +/* + * DAI Sync + * Synchronous LR (Left Right) clocks and Frame signals. + */ +#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */ +#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */ + +/* + * TDM + */ +#define SND_SOC_DAIFMT_TDM (1 << 6) + +/* + * DAI hardware signal inversions + */ +#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bclk + frm */ +#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ +#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ +#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ + +/* + * DAI hardware clock masters + * This is wrt the codec, the inverse is true for the interface + * i.e. if the codec is clk and frm master then the interface is + * clk and frame slave. + */ +#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ +#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ +#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ +#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ + +#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f +#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 +#define SND_SOC_DAIFMT_INV_MASK 0x0f00 +#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 + + +/* + * Master Clock Directions + */ +#define SND_SOC_CLOCK_IN 0 +#define SND_SOC_CLOCK_OUT 1 + +/* + * AC97 codec ID's bitmask + */ +#define SND_SOC_DAI_AC97_ID0 (1 << 0) +#define SND_SOC_DAI_AC97_ID1 (1 << 1) +#define SND_SOC_DAI_AC97_ID2 (1 << 2) +#define SND_SOC_DAI_AC97_ID3 (1 << 3) + struct snd_soc_device; struct snd_soc_pcm_stream; struct snd_soc_ops; struct snd_soc_dai_mode; struct snd_soc_pcm_runtime; struct snd_soc_dai; -struct snd_soc_platform; struct snd_soc_codec; +struct snd_soc_machine_config; struct soc_enum; struct snd_soc_ac97_ops; +struct snd_soc_clock_info; typedef int (*hw_write_t)(void *,const char* ,int); typedef int (*hw_read_t)(void *,char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops; -int snd_soc_register_platform(struct snd_soc_platform *platform); -void snd_soc_unregister_platform(struct snd_soc_platform *platform); - /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); -int snd_soc_init_card(struct snd_soc_device *socdev); +int snd_soc_register_card(struct snd_soc_device *socdev); /* set runtime hw params */ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, @@ -185,6 +263,27 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num); void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); +/* Digital Audio Interface clocking API.*/ +int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir); + +int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, + int div_id, int div); + +int snd_soc_dai_set_pll(struct snd_soc_dai *dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + +/* Digital Audio interface formatting */ +int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); + +int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int mask, int slots); + +int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); + +/* Digital Audio Interface mute */ +int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); + /* *Controls */ @@ -242,6 +341,61 @@ struct snd_soc_ops { int (*trigger)(struct snd_pcm_substream *, int); }; +/* ASoC DAI ops */ +struct snd_soc_dai_ops { + /* DAI clocking configuration */ + int (*set_sysclk)(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir); + int (*set_pll)(struct snd_soc_dai *dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); + + /* DAI format configuration */ + int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); + int (*set_tdm_slot)(struct snd_soc_dai *dai, + unsigned int mask, int slots); + int (*set_tristate)(struct snd_soc_dai *dai, int tristate); + + /* digital mute */ + int (*digital_mute)(struct snd_soc_dai *dai, int mute); +}; + +/* SoC DAI (Digital Audio Interface) */ +struct snd_soc_dai { + /* DAI description */ + char *name; + unsigned int id; + unsigned char type; + + /* DAI callbacks */ + int (*probe)(struct platform_device *pdev, + struct snd_soc_dai *dai); + void (*remove)(struct platform_device *pdev, + struct snd_soc_dai *dai); + int (*suspend)(struct platform_device *pdev, + struct snd_soc_dai *dai); + int (*resume)(struct platform_device *pdev, + struct snd_soc_dai *dai); + + /* ops */ + struct snd_soc_ops ops; + struct snd_soc_dai_ops dai_ops; + + /* DAI capabilities */ + struct snd_soc_pcm_stream capture; + struct snd_soc_pcm_stream playback; + + /* DAI runtime info */ + struct snd_pcm_runtime *runtime; + struct snd_soc_codec *codec; + unsigned int active; + unsigned char pop_wait:1; + void *dma_data; + + /* DAI private data */ + void *private_data; +}; + /* SoC Audio Codec */ struct snd_soc_codec { char *name; @@ -272,7 +426,6 @@ struct snd_soc_codec { short reg_cache_step; /* dapm */ - u32 pop_time; struct list_head dapm_widgets; struct list_head dapm_paths; enum snd_soc_bias_level bias_level; @@ -282,11 +435,6 @@ struct snd_soc_codec { /* codec DAI's */ struct snd_soc_dai *dai; unsigned int num_dai; - -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_reg; - struct dentry *debugfs_pop_time; -#endif }; /* codec device */ @@ -300,12 +448,13 @@ struct snd_soc_codec_device { /* SoC platform interface */ struct snd_soc_platform { char *name; - struct list_head list; int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); - int (*suspend)(struct snd_soc_dai *dai); - int (*resume)(struct snd_soc_dai *dai); + int (*suspend)(struct platform_device *pdev, + struct snd_soc_dai *dai); + int (*resume)(struct platform_device *pdev, + struct snd_soc_dai *dai); /* pcm creation and destruction */ int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, @@ -335,14 +484,9 @@ struct snd_soc_dai_link { struct snd_pcm *pcm; }; -/* SoC card */ -struct snd_soc_card { +/* SoC machine */ +struct snd_soc_machine { char *name; - struct device *dev; - - struct list_head list; - - int instantiated; int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); @@ -355,26 +499,23 @@ struct snd_soc_card { int (*resume_post)(struct platform_device *pdev); /* callbacks */ - int (*set_bias_level)(struct snd_soc_card *, + int (*set_bias_level)(struct snd_soc_machine *, enum snd_soc_bias_level level); /* CPU <--> Codec DAI links */ struct snd_soc_dai_link *dai_link; int num_links; - - struct snd_soc_device *socdev; - - struct snd_soc_platform *platform; - struct delayed_work delayed_work; - struct work_struct deferred_resume_work; }; /* SoC Device - the audio subsystem */ struct snd_soc_device { struct device *dev; - struct snd_soc_card *card; + struct snd_soc_machine *machine; + struct snd_soc_platform *platform; struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; + struct delayed_work delayed_work; + struct work_struct deferred_resume_work; void *codec_data; }; @@ -401,6 +542,4 @@ struct soc_enum { void *dapm; }; -#include <sound/soc-dai.h> - #endif diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h deleted file mode 100644 index 475ef8bb7dcd..000000000000 --- a/include/sound/uda134x.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * uda134x.h -- UDA134x ALSA SoC Codec driver - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _UDA134X_H -#define _UDA134X_H - -#include <sound/l3.h> - -struct uda134x_platform_data { - struct l3_pins l3; - void (*power) (int); - int model; -#define UDA134X_UDA1340 1 -#define UDA134X_UDA1341 2 -#define UDA134X_UDA1344 3 -}; - -#endif /* _UDA134X_H */ diff --git a/include/sound/version.h b/include/sound/version.h index 2b48237e23bf..4aafeda88634 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.18a" +#define CONFIG_SND_VERSION "1.0.18rc3" #define CONFIG_SND_DATE "" diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index a351dd0a09c7..7fa37e15f196 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c @@ -15,7 +15,6 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/string.h> -#include <sound/ac97_codec.h> /* * Let drivers decide whether they want to support given codec from their diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile index c3ee77fc4b2d..31cbe68fd42f 100644 --- a/sound/aoa/codecs/Makefile +++ b/sound/aoa/codecs/Makefile @@ -1,7 +1,3 @@ -snd-aoa-codec-onyx-objs := onyx.o -snd-aoa-codec-tas-objs := tas.o -snd-aoa-codec-toonie-objs := toonie.o - obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c index 15500b9d2da0..6a3837d480e5 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c @@ -37,7 +37,7 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa"); -#include "onyx.h" +#include "snd-aoa-codec-onyx.h" #include "../aoa.h" #include "../soundbus/soundbus.h" @@ -292,7 +292,7 @@ static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new capture_source_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* If we name this 'Input Source', it properly shows up in - * alsamixer as a selection, * but it's shown under the + * alsamixer as a selection, * but it's shown under the * 'Playback' category. * If I name it 'Capture Source', it shows up in strange * ways (two bools of which one can be selected at a @@ -477,7 +477,7 @@ static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol, ucontrol->value.iec958.status[3] = 0x3f; ucontrol->value.iec958.status[4] = 0x0f; - + return 0; } @@ -682,7 +682,7 @@ static int onyx_usable(struct codec_info_item *cii, onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); spdif_enabled = !!(v & ONYX_SPDIF_ENABLE); onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); - analog_enabled = + analog_enabled = (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT)) != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT); mutex_unlock(&onyx->mutex); @@ -882,7 +882,7 @@ static int onyx_init_codec(struct aoa_codec *codec) msleep(1); onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); msleep(1); - + if (onyx_register_init(onyx)) { printk(KERN_ERR PFX "failed to initialise onyx registers\n"); return -ENODEV; @@ -1069,7 +1069,7 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter) /* if that didn't work, try desperate mode for older * machines that have stuff missing from the device tree */ - + if (!of_device_is_compatible(busnode, "k2-i2c")) return -ENODEV; diff --git a/sound/aoa/codecs/onyx.h b/sound/aoa/codecs/snd-aoa-codec-onyx.h index ffd20254ff76..ffd20254ff76 100644 --- a/sound/aoa/codecs/onyx.h +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.h diff --git a/sound/aoa/codecs/tas-basstreble.h b/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h index 69b61136fd54..69b61136fd54 100644 --- a/sound/aoa/codecs/tas-basstreble.h +++ b/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h diff --git a/sound/aoa/codecs/tas-gain-table.h b/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h index 4cfa6757715e..4cfa6757715e 100644 --- a/sound/aoa/codecs/tas-gain-table.h +++ b/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 008e0f85097d..6c515b2b8bbd 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -71,9 +71,9 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("tas codec driver for snd-aoa"); -#include "tas.h" -#include "tas-gain-table.h" -#include "tas-basstreble.h" +#include "snd-aoa-codec-tas.h" +#include "snd-aoa-codec-tas-gain-table.h" +#include "snd-aoa-codec-tas-basstreble.h" #include "../aoa.h" #include "../soundbus/soundbus.h" @@ -880,7 +880,7 @@ static void tas_exit_codec(struct aoa_codec *codec) return; tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); } - + static struct i2c_driver tas_driver; diff --git a/sound/aoa/codecs/tas.h b/sound/aoa/codecs/snd-aoa-codec-tas.h index ae177e3466e6..ae177e3466e6 100644 --- a/sound/aoa/codecs/tas.h +++ b/sound/aoa/codecs/snd-aoa-codec-tas.h diff --git a/sound/aoa/codecs/toonie.c b/sound/aoa/codecs/snd-aoa-codec-toonie.c index f13827e17562..3c7d1d8a9a6f 100644 --- a/sound/aoa/codecs/toonie.c +++ b/sound/aoa/codecs/snd-aoa-codec-toonie.c @@ -131,7 +131,7 @@ static int __init toonie_init(void) toonie->codec.owner = THIS_MODULE; toonie->codec.init = toonie_init_codec; toonie->codec.exit = toonie_exit_codec; - + if (aoa_codec_register(&toonie->codec)) { kfree(toonie); return -EINVAL; diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile index a1596e88c718..62dc7287f663 100644 --- a/sound/aoa/core/Makefile +++ b/sound/aoa/core/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_SND_AOA) += snd-aoa.o -snd-aoa-objs := core.o \ - alsa.o \ - gpio-pmf.o \ - gpio-feature.o +snd-aoa-objs := snd-aoa-core.o \ + snd-aoa-alsa.o \ + snd-aoa-gpio-pmf.o \ + snd-aoa-gpio-feature.o diff --git a/sound/aoa/core/alsa.c b/sound/aoa/core/snd-aoa-alsa.c index 617850463582..17fe689ed287 100644 --- a/sound/aoa/core/alsa.c +++ b/sound/aoa/core/snd-aoa-alsa.c @@ -6,7 +6,7 @@ * GPL v2, can be found in COPYING. */ #include <linux/module.h> -#include "alsa.h" +#include "snd-aoa-alsa.h" static int index = -1; module_param(index, int, 0444); @@ -64,7 +64,7 @@ int aoa_snd_device_new(snd_device_type_t type, { struct snd_card *card = aoa_get_card(); int err; - + if (!card) return -ENOMEM; err = snd_device_new(card, type, device_data, ops); diff --git a/sound/aoa/core/alsa.h b/sound/aoa/core/snd-aoa-alsa.h index 9669e4489cab..9669e4489cab 100644 --- a/sound/aoa/core/alsa.h +++ b/sound/aoa/core/snd-aoa-alsa.h diff --git a/sound/aoa/core/core.c b/sound/aoa/core/snd-aoa-core.c index 10bec6c61382..19fdae400687 100644 --- a/sound/aoa/core/core.c +++ b/sound/aoa/core/snd-aoa-core.c @@ -10,7 +10,7 @@ #include <linux/module.h> #include <linux/list.h> #include "../aoa.h" -#include "alsa.h" +#include "snd-aoa-alsa.h" MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver"); MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c index c93ad5dec66b..805dcbff2257 100644 --- a/sound/aoa/core/gpio-feature.c +++ b/sound/aoa/core/snd-aoa-gpio-feature.c @@ -5,7 +5,7 @@ * * GPL v2, can be found in COPYING. * - * This file contains the GPIO control routines for + * This file contains the GPIO control routines for * direct (through feature calls) access to the GPIO * registers. */ diff --git a/sound/aoa/core/gpio-pmf.c b/sound/aoa/core/snd-aoa-gpio-pmf.c index 5ca2220eac7d..5ca2220eac7d 100644 --- a/sound/aoa/core/gpio-pmf.c +++ b/sound/aoa/core/snd-aoa-gpio-pmf.c diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile index da37c10eca51..55fc5e7e52cf 100644 --- a/sound/aoa/fabrics/Makefile +++ b/sound/aoa/fabrics/Makefile @@ -1,3 +1 @@ -snd-aoa-fabric-layout-objs += layout.o - obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index ad60f5d10e82..dea7abb082cd 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -66,7 +66,7 @@ struct layout { unsigned int layout_id; struct codec_connect_info codecs[MAX_CODECS_PER_BUS]; int flags; - + /* if busname is not assigned, we use 'Master' below, * so that our layout table doesn't need to be filled * too much. diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile index 1b949b2a4028..e57a5cf65655 100644 --- a/sound/aoa/soundbus/i2sbus/Makefile +++ b/sound/aoa/soundbus/i2sbus/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o -snd-aoa-i2sbus-objs := core.o pcm.o control.o +snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o diff --git a/sound/aoa/soundbus/i2sbus/control.c b/sound/aoa/soundbus/i2sbus/i2sbus-control.c index 87beb4ad4d63..87beb4ad4d63 100644 --- a/sound/aoa/soundbus/i2sbus/control.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.c diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index be468edf3ecb..b4590df07466 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -64,7 +64,7 @@ static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, struct dbdma_command_mem *r) { if (!r->space) return; - + dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, r->size, r->space, r->bus_addr); } @@ -247,7 +247,7 @@ static int i2sbus_add_dev(struct macio_dev *macio, * but request_resource doesn't know about parents and * contained resources... */ - dev->allocated_resource[i] = + dev->allocated_resource[i] = request_mem_region(dev->resources[i].start, dev->resources[i].end - dev->resources[i].start + 1, diff --git a/sound/aoa/soundbus/i2sbus/interface.h b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h index c6b5f5452d20..c6b5f5452d20 100644 --- a/sound/aoa/soundbus/i2sbus/interface.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index 59bacd365733..59bacd365733 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index befefd99e271..ff29654782c9 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h @@ -18,7 +18,7 @@ #include <asm/pmac_feature.h> #include <asm/dbdma.h> -#include "interface.h" +#include "i2sbus-interface.h" #include "../soundbus.h" struct i2sbus_control { diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 7bbdda041a99..66348c92f88d 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -95,26 +95,6 @@ config SND_SEQUENCER_OSS this will be compiled as a module. The module will be called snd-seq-oss. -config SND_HRTIMER - tristate "HR-timer backend support" - depends on HIGH_RES_TIMERS - select SND_TIMER - help - Say Y here to enable HR-timer backend for ALSA timer. ALSA uses - the hrtimer as a precise timing source. The ALSA sequencer code - also can use this timing source. - - To compile this driver as a module, choose M here: the module - will be called snd-hrtimer. - -config SND_SEQ_HRTIMER_DEFAULT - bool "Use HR-timer as default sequencer timer" - depends on SND_HRTIMER && SND_SEQUENCER - default y - help - Say Y here to use the HR-timer backend as the default sequencer - timer. - config SND_RTCTIMER tristate "RTC Timer support" depends on RTC @@ -134,7 +114,6 @@ config SND_RTCTIMER config SND_SEQ_RTCTIMER_DEFAULT bool "Use RTC as default sequencer timer" depends on SND_RTCTIMER && SND_SEQUENCER - depends on !SND_SEQ_HRTIMER_DEFAULT default y help Say Y here to use the RTC timer as the default sequencer diff --git a/sound/core/Makefile b/sound/core/Makefile index 4229052e7b91..d57125a5687d 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -17,14 +17,12 @@ snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o -snd-hrtimer-objs := hrtimer.o snd-rtctimer-objs := rtctimer.o snd-hwdep-objs := hwdep.o obj-$(CONFIG_SND) += snd.o obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o obj-$(CONFIG_SND_TIMER) += snd-timer.o -obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o diff --git a/sound/core/device.c b/sound/core/device.c index a67dfac08c03..c58d8227254c 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -98,7 +98,7 @@ int snd_device_free(struct snd_card *card, void *device_data) kfree(dev); return 0; } - snd_printd("device free %p (from %pF), not found\n", device_data, + snd_printd("device free %p (from %p), not found\n", device_data, __builtin_return_address(0)); return -ENXIO; } @@ -135,7 +135,7 @@ int snd_device_disconnect(struct snd_card *card, void *device_data) } return 0; } - snd_printd("device disconnect %p (from %pF), not found\n", device_data, + snd_printd("device disconnect %p (from %p), not found\n", device_data, __builtin_return_address(0)); return -ENXIO; } diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c deleted file mode 100644 index c1d285921f80..000000000000 --- a/sound/core/hrtimer.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * ALSA timer back-end using hrtimer - * Copyright (C) 2008 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/hrtimer.h> -#include <sound/core.h> -#include <sound/timer.h> - -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); -MODULE_DESCRIPTION("ALSA hrtimer backend"); -MODULE_LICENSE("GPL"); - -MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER)); - -#define NANO_SEC 1000000000UL /* 10^9 in sec */ -static unsigned int resolution; - -struct snd_hrtimer { - struct snd_timer *timer; - struct hrtimer hrt; -}; - -static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) -{ - struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); - struct snd_timer *t = stime->timer; - hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); - snd_timer_interrupt(stime->timer, t->sticks); - return HRTIMER_RESTART; -} - -static int snd_hrtimer_open(struct snd_timer *t) -{ - struct snd_hrtimer *stime; - - stime = kmalloc(sizeof(*stime), GFP_KERNEL); - if (!stime) - return -ENOMEM; - hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - stime->timer = t; - stime->hrt.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED; - stime->hrt.function = snd_hrtimer_callback; - t->private_data = stime; - return 0; -} - -static int snd_hrtimer_close(struct snd_timer *t) -{ - struct snd_hrtimer *stime = t->private_data; - - if (stime) { - hrtimer_cancel(&stime->hrt); - kfree(stime); - t->private_data = NULL; - } - return 0; -} - -static int snd_hrtimer_start(struct snd_timer *t) -{ - struct snd_hrtimer *stime = t->private_data; - - hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), - HRTIMER_MODE_REL); - return 0; -} - -static int snd_hrtimer_stop(struct snd_timer *t) -{ - struct snd_hrtimer *stime = t->private_data; - - hrtimer_cancel(&stime->hrt); - return 0; -} - -static struct snd_timer_hardware hrtimer_hw = { - .flags = SNDRV_TIMER_HW_AUTO, - .open = snd_hrtimer_open, - .close = snd_hrtimer_close, - .start = snd_hrtimer_start, - .stop = snd_hrtimer_stop, -}; - -/* - * entry functions - */ - -static struct snd_timer *mytimer; - -static int __init snd_hrtimer_init(void) -{ - struct snd_timer *timer; - struct timespec tp; - int err; - - hrtimer_get_res(CLOCK_MONOTONIC, &tp); - if (tp.tv_sec > 0 || !tp.tv_nsec) { - snd_printk(KERN_ERR - "snd-hrtimer: Invalid resolution %u.%09u", - (unsigned)tp.tv_sec, (unsigned)tp.tv_nsec); - return -EINVAL; - } - resolution = tp.tv_nsec; - - /* Create a new timer and set up the fields */ - err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER, - &timer); - if (err < 0) - return err; - - timer->module = THIS_MODULE; - strcpy(timer->name, "HR timer"); - timer->hw = hrtimer_hw; - timer->hw.resolution = resolution; - timer->hw.ticks = NANO_SEC / resolution; - - err = snd_timer_global_register(timer); - if (err < 0) { - snd_timer_global_free(timer); - return err; - } - mytimer = timer; /* remember this */ - - return 0; -} - -static void __exit snd_hrtimer_exit(void) -{ - if (mytimer) { - snd_timer_global_free(mytimer); - mytimer = NULL; - } -} - -module_init(snd_hrtimer_init); -module_exit(snd_hrtimer_exit); diff --git a/sound/core/info.c b/sound/core/info.c index 70fa87189f36..527b207462b0 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -653,23 +653,6 @@ int snd_info_card_register(struct snd_card *card) } /* - * called on card->id change - */ -void snd_info_card_id_change(struct snd_card *card) -{ - mutex_lock(&info_mutex); - if (card->proc_root_link) { - snd_remove_proc_entry(snd_proc_root, card->proc_root_link); - card->proc_root_link = NULL; - } - if (strcmp(card->id, card->proc_root->name)) - card->proc_root_link = proc_symlink(card->id, - snd_proc_root, - card->proc_root->name); - mutex_unlock(&info_mutex); -} - -/* * de-register the card proc file * called from init.c */ diff --git a/sound/core/init.c b/sound/core/init.c index 0d5520c415d3..b47ff8b44be8 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -533,65 +533,6 @@ static void choose_default_id(struct snd_card *card) } } -#ifndef CONFIG_SYSFS_DEPRECATED -static ssize_t -card_id_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct snd_card *card = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)"); -} - -static ssize_t -card_id_store_attr(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_card *card = dev_get_drvdata(dev); - char buf1[sizeof(card->id)]; - size_t copy = count > sizeof(card->id) - 1 ? - sizeof(card->id) - 1 : count; - size_t idx; - int c; - - for (idx = 0; idx < copy; idx++) { - c = buf[idx]; - if (!isalnum(c) && c != '_' && c != '-') - return -EINVAL; - } - memcpy(buf1, buf, copy); - buf1[copy] = '\0'; - mutex_lock(&snd_card_mutex); - if (!snd_info_check_reserved_words(buf1)) { - __exist: - mutex_unlock(&snd_card_mutex); - return -EEXIST; - } - for (idx = 0; idx < snd_ecards_limit; idx++) { - if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) - goto __exist; - } - strcpy(card->id, buf1); - snd_info_card_id_change(card); - mutex_unlock(&snd_card_mutex); - - return count; -} - -static struct device_attribute card_id_attrs = - __ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr); - -static ssize_t -card_number_show_attr(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct snd_card *card = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1); -} - -static struct device_attribute card_number_attrs = - __ATTR(number, S_IRUGO, card_number_show_attr, NULL); -#endif /* CONFIG_SYSFS_DEPRECATED */ - /** * snd_card_register - register the soundcard * @card: soundcard structure @@ -612,7 +553,7 @@ int snd_card_register(struct snd_card *card) #ifndef CONFIG_SYSFS_DEPRECATED if (!card->card_dev) { card->card_dev = device_create(sound_class, card->dev, - MKDEV(0, 0), card, + MKDEV(0, 0), NULL, "card%i", card->number); if (IS_ERR(card->card_dev)) card->card_dev = NULL; @@ -635,16 +576,6 @@ int snd_card_register(struct snd_card *card) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); #endif -#ifndef CONFIG_SYSFS_DEPRECATED - if (card->card_dev) { - err = device_create_file(card->card_dev, &card_id_attrs); - if (err < 0) - return err; - err = device_create_file(card->card_dev, &card_number_attrs); - if (err < 0) - return err; - } -#endif return 0; } diff --git a/sound/core/jack.c b/sound/core/jack.c index 284432f427f4..bd2d9e6b55e9 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -34,7 +34,6 @@ static int snd_jack_dev_free(struct snd_device *device) else input_free_device(jack->input_dev); - kfree(jack->id); kfree(jack); return 0; @@ -88,7 +87,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (jack == NULL) return -ENOMEM; - jack->id = kstrdup(id, GFP_KERNEL); + jack->id = id; jack->input_dev = input_allocate_device(); if (jack->input_dev == NULL) { @@ -103,9 +102,6 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_HEADPHONE) input_set_capability(jack->input_dev, EV_SW, SW_HEADPHONE_INSERT); - if (type & SND_JACK_LINEOUT) - input_set_capability(jack->input_dev, EV_SW, - SW_LINEOUT_INSERT); if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT); @@ -157,9 +153,6 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_HEADPHONE) input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, status & SND_JACK_HEADPHONE); - if (jack->type & SND_JACK_LINEOUT) - input_report_switch(jack->input_dev, SW_LINEOUT_INSERT, - status & SND_JACK_LINEOUT); if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE); diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index bf09a5ad1865..ee0f8405ab35 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -43,9 +43,7 @@ int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL; int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE; int seq_default_timer_card = -1; int seq_default_timer_device = -#ifdef CONFIG_SND_SEQ_HRTIMER_DEFAULT - SNDRV_TIMER_GLOBAL_HRTIMER -#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT) +#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT SNDRV_TIMER_GLOBAL_RTC #else SNDRV_TIMER_GLOBAL_SYSTEM diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 0bcf14640fde..255fd18b9aec 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -163,7 +163,7 @@ config SND_ML403_AC97CR config SND_AC97_POWER_SAVE bool "AC97 Power-Saving Mode" - depends on SND_AC97_CODEC + depends on SND_AC97_CODEC && EXPERIMENTAL default n help Say Y here to enable the aggressive power-saving support of diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 2a02f704f366..1899cf0685bc 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -96,7 +96,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) return -EINVAL; hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED; + pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ; pcsp_chip.timer.function = pcsp_do_timer; card = snd_card_new(index, id, THIS_MODULE, 0); @@ -188,8 +188,10 @@ static int __devexit pcsp_remove(struct platform_device *dev) static void pcsp_stop_beep(struct snd_pcsp *chip) { - pcsp_sync_stop(chip); - pcspkr_stop_sound(); + spin_lock_irq(&chip->substream_lock); + if (!chip->playback_substream) + pcspkr_stop_sound(); + spin_unlock_irq(&chip->substream_lock); } #ifdef CONFIG_PM diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index cdef2664218f..1d661f795e8c 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h @@ -62,8 +62,6 @@ struct snd_pcsp { unsigned short port, irq, dma; spinlock_t substream_lock; struct snd_pcm_substream *playback_substream; - unsigned int fmt_size; - unsigned int is_signed; size_t playback_ptr; size_t period_ptr; atomic_t timer_active; @@ -79,7 +77,6 @@ struct snd_pcsp { extern struct snd_pcsp pcsp_chip; extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle); -extern void pcsp_sync_stop(struct snd_pcsp *chip); extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 84cc2658c05b..1f42e4063118 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -8,7 +8,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/interrupt.h> #include <sound/pcm.h> #include <asm/io.h> #include "pcsp.h" @@ -20,57 +19,61 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround " #define DMIX_WANTS_S16 1 -/* - * Call snd_pcm_period_elapsed in a tasklet - * This avoids spinlock messes and long-running irq contexts - */ -static void pcsp_call_pcm_elapsed(unsigned long priv) -{ - if (atomic_read(&pcsp_chip.timer_active)) { - struct snd_pcm_substream *substream; - substream = pcsp_chip.playback_substream; - if (substream) - snd_pcm_period_elapsed(substream); - } -} - -static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); - -/* write the port and returns the next expire time in ns; - * called at the trigger-start and in hrtimer callback - */ -static unsigned long pcsp_timer_update(struct hrtimer *handle) +enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) { unsigned char timer_cnt, val; + int fmt_size, periods_elapsed; u64 ns; + size_t period_bytes, buffer_bytes; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); - unsigned long flags; if (chip->thalf) { outb(chip->val61, 0x61); chip->thalf = 0; if (!atomic_read(&chip->timer_active)) - return 0; - return chip->ns_rem; + return HRTIMER_NORESTART; + hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer), + ktime_set(0, chip->ns_rem)); + return HRTIMER_RESTART; } - if (!atomic_read(&chip->timer_active)) - return 0; + spin_lock_irq(&chip->substream_lock); + /* Takashi Iwai says regarding this extra lock: + + If the irq handler handles some data on the DMA buffer, it should + do snd_pcm_stream_lock(). + That protects basically against all races among PCM callbacks, yes. + However, there are two remaining issues: + 1. The substream pointer you try to lock isn't protected _before_ + this lock yet. + 2. snd_pcm_period_elapsed() itself acquires the lock. + The requirement of another lock is because of 1. When you get + chip->playback_substream, it's not protected. + Keeping this lock while snd_pcm_period_elapsed() assures the substream + is still protected (at least, not released). And the other status is + handled properly inside snd_pcm_stream_lock() in + snd_pcm_period_elapsed(). + + */ + if (!chip->playback_substream) + goto exit_nr_unlock1; substream = chip->playback_substream; - if (!substream) - return 0; + snd_pcm_stream_lock(substream); + if (!atomic_read(&chip->timer_active)) + goto exit_nr_unlock2; runtime = substream->runtime; + fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3; /* assume it is mono! */ - val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1]; - if (chip->is_signed) + val = runtime->dma_area[chip->playback_ptr + fmt_size - 1]; + if (snd_pcm_format_signed(runtime->format)) val ^= 0x80; timer_cnt = val * CUR_DIV() / 256; if (timer_cnt && chip->enable) { - spin_lock_irqsave(&i8253_lock, flags); + spin_lock(&i8253_lock); if (!nforce_wa) { outb_p(chip->val61, 0x61); outb_p(timer_cnt, 0x42); @@ -79,39 +82,12 @@ static unsigned long pcsp_timer_update(struct hrtimer *handle) outb(chip->val61 ^ 2, 0x61); chip->thalf = 1; } - spin_unlock_irqrestore(&i8253_lock, flags); + spin_unlock(&i8253_lock); } - chip->ns_rem = PCSP_PERIOD_NS(); - ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); - chip->ns_rem -= ns; - return ns; -} - -enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) -{ - struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); - struct snd_pcm_substream *substream; - int periods_elapsed, pointer_update; - size_t period_bytes, buffer_bytes; - unsigned long ns; - unsigned long flags; - - pointer_update = !chip->thalf; - ns = pcsp_timer_update(handle); - if (!ns) - return HRTIMER_NORESTART; - - /* update the playback position */ - substream = chip->playback_substream; - if (!substream) - return HRTIMER_NORESTART; - period_bytes = snd_pcm_lib_period_bytes(substream); buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - - spin_lock_irqsave(&chip->substream_lock, flags); - chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size; + chip->playback_ptr += PCSP_INDEX_INC() * fmt_size; periods_elapsed = chip->playback_ptr - chip->period_ptr; if (periods_elapsed < 0) { #if PCSP_DEBUG @@ -126,30 +102,41 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) * or ALSA will BUG on us. */ chip->playback_ptr %= buffer_bytes; + snd_pcm_stream_unlock(substream); + if (periods_elapsed) { + snd_pcm_period_elapsed(substream); chip->period_ptr += periods_elapsed * period_bytes; chip->period_ptr %= buffer_bytes; } - spin_unlock_irqrestore(&chip->substream_lock, flags); - if (periods_elapsed) - tasklet_schedule(&pcsp_pcm_tasklet); + spin_unlock_irq(&chip->substream_lock); - hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns)); + if (!atomic_read(&chip->timer_active)) + return HRTIMER_NORESTART; + chip->ns_rem = PCSP_PERIOD_NS(); + ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); + chip->ns_rem -= ns; + hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer), + ktime_set(0, ns)); return HRTIMER_RESTART; + +exit_nr_unlock2: + snd_pcm_stream_unlock(substream); +exit_nr_unlock1: + spin_unlock_irq(&chip->substream_lock); + return HRTIMER_NORESTART; } -static int pcsp_start_playing(struct snd_pcsp *chip) +static void pcsp_start_playing(struct snd_pcsp *chip) { - unsigned long ns; - #if PCSP_DEBUG printk(KERN_INFO "PCSP: start_playing called\n"); #endif if (atomic_read(&chip->timer_active)) { printk(KERN_ERR "PCSP: Timer already active\n"); - return -EIO; + return; } spin_lock(&i8253_lock); @@ -159,12 +146,7 @@ static int pcsp_start_playing(struct snd_pcsp *chip) atomic_set(&chip->timer_active, 1); chip->thalf = 0; - ns = pcsp_timer_update(&pcsp_chip.timer); - if (!ns) - return -EIO; - - hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL); - return 0; + hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL); } static void pcsp_stop_playing(struct snd_pcsp *chip) @@ -183,35 +165,26 @@ static void pcsp_stop_playing(struct snd_pcsp *chip) spin_unlock(&i8253_lock); } -/* - * Force to stop and sync the stream - */ -void pcsp_sync_stop(struct snd_pcsp *chip) -{ - local_irq_disable(); - pcsp_stop_playing(chip); - local_irq_enable(); - hrtimer_cancel(&chip->timer); - tasklet_kill(&pcsp_pcm_tasklet); -} - static int snd_pcsp_playback_close(struct snd_pcm_substream *substream) { struct snd_pcsp *chip = snd_pcm_substream_chip(substream); #if PCSP_DEBUG printk(KERN_INFO "PCSP: close called\n"); #endif - pcsp_sync_stop(chip); + if (atomic_read(&chip->timer_active)) { + printk(KERN_ERR "PCSP: timer still active\n"); + pcsp_stop_playing(chip); + } + spin_lock_irq(&chip->substream_lock); chip->playback_substream = NULL; + spin_unlock_irq(&chip->substream_lock); return 0; } static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct snd_pcsp *chip = snd_pcm_substream_chip(substream); int err; - pcsp_sync_stop(chip); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) @@ -221,11 +194,9 @@ static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream) { - struct snd_pcsp *chip = snd_pcm_substream_chip(substream); #if PCSP_DEBUG printk(KERN_INFO "PCSP: hw_free called\n"); #endif - pcsp_sync_stop(chip); return snd_pcm_lib_free_pages(substream); } @@ -241,12 +212,8 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream) snd_pcm_lib_period_bytes(substream), substream->runtime->periods); #endif - pcsp_sync_stop(chip); chip->playback_ptr = 0; chip->period_ptr = 0; - chip->fmt_size = - snd_pcm_format_physical_width(substream->runtime->format) >> 3; - chip->is_signed = snd_pcm_format_signed(substream->runtime->format); return 0; } @@ -259,7 +226,8 @@ static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - return pcsp_start_playing(chip); + pcsp_start_playing(chip); + break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: pcsp_stop_playing(chip); @@ -274,11 +242,7 @@ static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream *substream) { struct snd_pcsp *chip = snd_pcm_substream_chip(substream); - unsigned int pos; - spin_lock(&chip->substream_lock); - pos = chip->playback_ptr; - spin_unlock(&chip->substream_lock); - return bytes_to_frames(substream->runtime, pos); + return bytes_to_frames(substream->runtime, chip->playback_ptr); } static struct snd_pcm_hardware snd_pcsp_playback = { @@ -315,7 +279,9 @@ static int snd_pcsp_playback_open(struct snd_pcm_substream *substream) return -EBUSY; } runtime->hw = snd_pcsp_playback; + spin_lock_irq(&chip->substream_lock); chip->playback_substream = substream; + spin_unlock_irq(&chip->substream_lock); return 0; } diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 6e3a1848447c..7003711f4fcc 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -208,8 +208,7 @@ config SND_OXYGEN * AuzenTech X-Meridian * Bgears b-Enspirer * Club3D Theatron DTS - * HT-Omega Claro (plus) - * HT-Omega Claro halo (XT) + * HT-Omega Claro * Razer Barracuda AC-1 * Sondigo Inferno @@ -498,7 +497,129 @@ config SND_FM801_TEA575X depends on SND_FM801_TEA575X_BOOL default SND_FM801 -source "sound/pci/hda/Kconfig" +config SND_HDA_INTEL + tristate "Intel HD Audio" + select SND_PCM + select SND_VMASTER + help + Say Y here to include support for Intel "High Definition + Audio" (Azalia) motherboard devices. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-intel. + +config SND_HDA_HWDEP + bool "Build hwdep interface for HD-audio driver" + depends on SND_HDA_INTEL + select SND_HWDEP + help + Say Y here to build a hwdep interface for HD-audio driver. + This interface can be used for out-of-band communication + with codecs for debugging purposes. + +config SND_HDA_INPUT_BEEP + bool "Support digital beep via input layer" + depends on SND_HDA_INTEL + depends on INPUT=y || INPUT=SND_HDA_INTEL + help + Say Y here to build a digital beep interface for HD-audio + driver. This interface is used to generate digital beeps. + +config SND_HDA_CODEC_REALTEK + bool "Build Realtek HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Realtek HD-audio codec support in + snd-hda-intel driver, such as ALC880. + +config SND_HDA_CODEC_ANALOG + bool "Build Analog Device HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Analog Device HD-audio codec support in + snd-hda-intel driver, such as AD1986A. + +config SND_HDA_CODEC_SIGMATEL + bool "Build IDT/Sigmatel HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include IDT (Sigmatel) HD-audio codec support in + snd-hda-intel driver, such as STAC9200. + +config SND_HDA_CODEC_VIA + bool "Build VIA HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include VIA HD-audio codec support in + snd-hda-intel driver, such as VT1708. + +config SND_HDA_CODEC_ATIHDMI + bool "Build ATI HDMI HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include ATI HDMI HD-audio codec support in + snd-hda-intel driver, such as ATI RS600 HDMI. + +config SND_HDA_CODEC_NVHDMI + bool "Build NVIDIA HDMI HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include NVIDIA HDMI HD-audio codec support in + snd-hda-intel driver, such as NVIDIA MCP78 HDMI. + +config SND_HDA_CODEC_CONEXANT + bool "Build Conexant HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Conexant HD-audio codec support in + snd-hda-intel driver, such as CX20549. + +config SND_HDA_CODEC_CMEDIA + bool "Build C-Media HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include C-Media HD-audio codec support in + snd-hda-intel driver, such as CMI9880. + +config SND_HDA_CODEC_SI3054 + bool "Build Silicon Labs 3054 HD-modem codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Silicon Labs 3054 HD-modem codec + (and compatibles) support in snd-hda-intel driver. + +config SND_HDA_GENERIC + bool "Enable generic HD-audio codec parser" + depends on SND_HDA_INTEL + default y + help + Say Y here to enable the generic HD-audio codec parser + in snd-hda-intel driver. + +config SND_HDA_POWER_SAVE + bool "Aggressive power-saving on HD-audio" + depends on SND_HDA_INTEL && EXPERIMENTAL + help + Say Y here to enable more aggressive power-saving mode on + HD-audio driver. The power-saving timeout can be configured + via power_save option or over sysfs on-the-fly. + +config SND_HDA_POWER_SAVE_DEFAULT + int "Default time-out for HD-audio power-save mode" + depends on SND_HDA_POWER_SAVE + default 0 + help + The default time-out value in seconds for HD-audio automatic + power-save mode. 0 means to disable the power-save mode. config SND_HDSP tristate "RME Hammerfall DSP Audio" diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index e2b843b4f9d0..bd510eceff1f 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -175,7 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x574d4C04, 0xffffffff, "WM9704M,WM9704Q", patch_wolfson04, NULL}, { 0x574d4C05, 0xffffffff, "WM9705,WM9710", patch_wolfson05, NULL}, { 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL}, -{ 0x574d4C12, 0xffffffff, "WM9711,WM9712,WM9715", patch_wolfson11, NULL}, +{ 0x574d4C12, 0xffffffff, "WM9711,WM9712", patch_wolfson11, NULL}, { 0x574d4c13, 0xffffffff, "WM9713,WM9714", patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF}, { 0x594d4800, 0xffffffff, "YMF743", patch_yamaha_ymf743, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 2c7cd97d2234..6e831aff1bd0 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2832,8 +2832,6 @@ static int patch_alc655(struct snd_ac97 * ac97) val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ else val |= (1 << 1); /* Pin 47 is spdif input pin */ - /* this seems missing on some hardwares */ - ac97->ext_id |= AC97_EI_SPDIF; } val &= ~(1 << 12); /* vref enable */ snd_ac97_write_cache(ac97, 0x7a, val); diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 1c14ff424116..74175fc80c7f 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -686,7 +686,7 @@ struct snd_ca0106 { spinlock_t emu_lock; struct snd_ac97 *ac97; - struct snd_pcm *pcm[4]; + struct snd_pcm *pcm; struct snd_ca0106_channel playback_channels[4]; struct snd_ca0106_channel capture_channels[4]; @@ -703,11 +703,6 @@ struct snd_ca0106 { struct snd_ca_midi midi2; u16 spi_dac_reg[16]; - -#ifdef CONFIG_PM -#define NUM_SAVED_VOLUMES 9 - unsigned int saved_vol[NUM_SAVED_VOLUMES]; -#endif }; int snd_ca0106_mixer(struct snd_ca0106 *emu); @@ -726,11 +721,3 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value); int snd_ca0106_spi_write(struct snd_ca0106 * emu, unsigned int data); - -#ifdef CONFIG_PM -void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip); -void snd_ca0106_mixer_resume(struct snd_ca0106 *chip); -#else -#define snd_ca0106_mixer_suspend(chip) do { } while (0) -#define snd_ca0106_mixer_resume(chip) do { } while (0) -#endif diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index cea8a7cdb1d5..88fbf285d2b7 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -847,18 +847,15 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, struct snd_pcm_substream *s; u32 basic = 0; u32 extended = 0; - u32 bits; - int running = 0; + int running=0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - running = 1; + running=1; break; case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: default: - running = 0; + running=0; break; } snd_pcm_group_for_each_entry(s, substream) { @@ -868,32 +865,22 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; - /* snd_printk("channel=%d\n",channel); */ + //snd_printk("channel=%d\n",channel); epcm->running = running; - basic |= (0x1 << channel); - extended |= (0x10 << channel); + basic |= (0x1<<channel); + extended |= (0x10<<channel); snd_pcm_trigger_done(s, substream); } - /* snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); */ + //snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); - bits |= extended; - snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); - bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); - bits |= basic; - snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); + snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended)); + snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic)); break; case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - bits = snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0); - bits &= ~basic; - snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, bits); - bits = snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0); - bits &= ~extended; - snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, bits); + snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); + snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended)); break; default: result = -EINVAL; @@ -1116,13 +1103,21 @@ static int snd_ca0106_ac97(struct snd_ca0106 *chip) return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } -static void ca0106_stop_chip(struct snd_ca0106 *chip); - static int snd_ca0106_free(struct snd_ca0106 *chip) { - if (chip->res_port != NULL) { - /* avoid access to already used hardware */ - ca0106_stop_chip(chip); + if (chip->res_port != NULL) { /* avoid access to already used hardware */ + // disable interrupts + snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); + outl(0, chip->port + INTE); + snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); + udelay(1000); + // disable audio + //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); + outl(0, chip->port + HCFG); + /* FIXME: We need to stop and DMA transfers here. + * But as I am not sure how yet, we cannot from the dma pages. + * So we can fix: snd-malloc: Memory leak? pages not freed = 8 + */ } if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1208,14 +1203,15 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) +static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; - err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); - if (err < 0) + if (rpcm) + *rpcm = NULL; + if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) return err; pcm->private_data = emu; @@ -1242,6 +1238,7 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "CA0106"); + emu->pcm = pcm; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; @@ -1263,7 +1260,8 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) return err; } - emu->pcm[device] = pcm; + if (rpcm) + *rpcm = pcm; return 0; } @@ -1303,9 +1301,89 @@ static unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ }; -static void ca0106_init_chip(struct snd_ca0106 *chip) +static int __devinit snd_ca0106_create(int dev, struct snd_card *card, + struct pci_dev *pci, + struct snd_ca0106 **rchip) { + struct snd_ca0106 *chip; + struct snd_ca0106_details *c; + int err; int ch; + static struct snd_device_ops ops = { + .dev_free = snd_ca0106_dev_free, + }; + + *rchip = NULL; + + if ((err = pci_enable_device(pci)) < 0) + return err; + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { + printk(KERN_ERR "error to set 32bit mask DMA\n"); + pci_disable_device(pci); + return -ENXIO; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + pci_disable_device(pci); + return -ENOMEM; + } + + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + spin_lock_init(&chip->emu_lock); + + chip->port = pci_resource_start(pci, 0); + if ((chip->res_port = request_region(chip->port, 0x20, + "snd_ca0106")) == NULL) { + snd_ca0106_free(chip); + printk(KERN_ERR "cannot allocate the port\n"); + return -EBUSY; + } + + if (request_irq(pci->irq, snd_ca0106_interrupt, + IRQF_SHARED, "snd_ca0106", chip)) { + snd_ca0106_free(chip); + printk(KERN_ERR "cannot grab irq\n"); + return -EBUSY; + } + chip->irq = pci->irq; + + /* This stores the periods table. */ + if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { + snd_ca0106_free(chip); + return -ENOMEM; + } + + pci_set_master(pci); + /* read serial */ + pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); + pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); +#if 1 + printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, + pci->revision, chip->serial); +#endif + strcpy(card->driver, "CA0106"); + strcpy(card->shortname, "CA0106"); + + for (c = ca0106_chip_details; c->serial; c++) { + if (subsystem[dev]) { + if (c->serial == subsystem[dev]) + break; + } else if (c->serial == chip->serial) + break; + } + chip->details = c; + if (subsystem[dev]) { + printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", + c->name, chip->serial, subsystem[dev]); + } + + sprintf(card->longname, "%s at 0x%lx irq %i", + c->name, chip->port, chip->irq); outl(0, chip->port + INTE); @@ -1323,31 +1401,31 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) * AN = 0 (Audio data) * P = 0 (Consumer) */ - chip->spdif_bits[0] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; - snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); + snd_ca0106_ptr_write(chip, SPCS0, 0, + chip->spdif_bits[0] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); /* Only SPCS1 has been tested */ - chip->spdif_bits[1] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; - snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); - chip->spdif_bits[2] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; - snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); - chip->spdif_bits[3] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; - snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); + snd_ca0106_ptr_write(chip, SPCS1, 0, + chip->spdif_bits[1] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + snd_ca0106_ptr_write(chip, SPCS2, 0, + chip->spdif_bits[2] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + snd_ca0106_ptr_write(chip, SPCS3, 0, + chip->spdif_bits[3] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); @@ -1355,53 +1433,36 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) /* Write 0x8000 to AC97_REC_GAIN to mute it. */ outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); outw(0x8000, chip->port + AC97DATA); -#if 0 /* FIXME: what are these? */ +#if 0 snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); #endif - /* OSS drivers set this. */ - /* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */ - + //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); - /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. - * Use 0x000f0000 for surround71 - */ - snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); - + snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ chip->spdif_enable = 0; /* Set digital SPDIF output off */ - /*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */ - /*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */ - - /* goes to 0x40c80000 when doing SPDIF IN/OUT */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); - /* (Mute) CAPTURE feedback into PLAYBACK volume. - * Only lower 16 bits matter. - */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); - /* SPDIF IN Volume */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); - /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); + //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ + //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); - - for (ch = 0; ch < 4; ch++) { - /* Only high 16 bits matter */ - snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); + for(ch = 0; ch < 4; ch++) { + snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); -#if 0 /* Mute */ - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); -#endif + //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ + //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ } if (chip->details->i2c_adc == 1) { /* Select MIC, Line in, TAD in, AUX in */ @@ -1420,56 +1481,44 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) chip->capture_source = 3; } - if (chip->details->gpio_type == 2) { - /* The SB0438 use GPIO differently. */ - /* FIXME: Still need to find out what the other GPIO bits do. - * E.g. For digital spdif out. - */ + if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ + /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); - /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ + //outl(0x00f0e000, chip->port+GPIO); /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ - } else if (chip->details->gpio_type == 1) { - /* The SB0410 and SB0413 use GPIO differently. */ - /* FIXME: Still need to find out what the other GPIO bits do. - * E.g. For digital spdif out. - */ + } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ + /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); - /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ + //outl(0x00f0e000, chip->port+GPIO); /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ - /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ + //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ } snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ - /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ - /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ - /* outl(0x00001409, chip->port+HCFG); */ - /* outl(0x00000009, chip->port+HCFG); */ - /* AC97 2.0, Enable outputs. */ - outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); + //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); + //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ + //outl(0x00000009, chip->port+HCFG); + outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ - if (chip->details->i2c_adc == 1) { - /* The SB0410 and SB0413 use I2C to control ADC. */ + if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ int size, n; size = ARRAY_SIZE(i2c_adc_init); - /* snd_printk("I2C:array size=0x%x\n", size); */ - for (n = 0; n < size; n++) - snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], - i2c_adc_init[n][1]); - for (n = 0; n < 4; n++) { - chip->i2c_capture_volume[n][0] = 0xcf; - chip->i2c_capture_volume[n][1] = 0xcf; + //snd_printk("I2C:array size=0x%x\n", size); + for (n=0; n < size; n++) { + snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); + } + for (n=0; n < 4; n++) { + chip->i2c_capture_volume[n][0]= 0xcf; + chip->i2c_capture_volume[n][1]= 0xcf; } - chip->i2c_capture_source = 2; /* Line in */ - /* Enable Line-in capture. MIC in currently untested. */ - /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ + chip->i2c_capture_source=2; /* Line in */ + //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ } - - if (chip->details->spi_dac == 1) { - /* The SB0570 use SPI to control DAC. */ + if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ int size, n; size = ARRAY_SIZE(spi_dac_init); @@ -1481,112 +1530,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) chip->spi_dac_reg[reg] = spi_dac_init[n]; } } -} - -static void ca0106_stop_chip(struct snd_ca0106 *chip) -{ - /* disable interrupts */ - snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); - outl(0, chip->port + INTE); - snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); - udelay(1000); - /* disable audio */ - /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ - outl(0, chip->port + HCFG); - /* FIXME: We need to stop and DMA transfers here. - * But as I am not sure how yet, we cannot from the dma pages. - * So we can fix: snd-malloc: Memory leak? pages not freed = 8 - */ -} -static int __devinit snd_ca0106_create(int dev, struct snd_card *card, - struct pci_dev *pci, - struct snd_ca0106 **rchip) -{ - struct snd_ca0106 *chip; - struct snd_ca0106_details *c; - int err; - static struct snd_device_ops ops = { - .dev_free = snd_ca0106_dev_free, - }; - - *rchip = NULL; - - err = pci_enable_device(pci); - if (err < 0) - return err; - if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || - pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { - printk(KERN_ERR "error to set 32bit mask DMA\n"); - pci_disable_device(pci); - return -ENXIO; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } - - chip->card = card; - chip->pci = pci; - chip->irq = -1; - - spin_lock_init(&chip->emu_lock); - - chip->port = pci_resource_start(pci, 0); - chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); - if (!chip->res_port) { - snd_ca0106_free(chip); - printk(KERN_ERR "cannot allocate the port\n"); - return -EBUSY; - } - - if (request_irq(pci->irq, snd_ca0106_interrupt, - IRQF_SHARED, "snd_ca0106", chip)) { - snd_ca0106_free(chip); - printk(KERN_ERR "cannot grab irq\n"); - return -EBUSY; - } - chip->irq = pci->irq; - - /* This stores the periods table. */ - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), - 1024, &chip->buffer) < 0) { - snd_ca0106_free(chip); - return -ENOMEM; - } - - pci_set_master(pci); - /* read serial */ - pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); - printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", - chip->model, pci->revision, chip->serial); - strcpy(card->driver, "CA0106"); - strcpy(card->shortname, "CA0106"); - - for (c = ca0106_chip_details; c->serial; c++) { - if (subsystem[dev]) { - if (c->serial == subsystem[dev]) - break; - } else if (c->serial == chip->serial) - break; - } - chip->details = c; - if (subsystem[dev]) { - printk(KERN_INFO "snd-ca0106: Sound card name=%s, " - "subsystem=0x%x. Forced to subsystem=0x%x\n", - c->name, chip->serial, subsystem[dev]); - } - - sprintf(card->longname, "%s at 0x%lx irq %i", - c->name, chip->port, chip->irq); - - ca0106_init_chip(chip); - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) { + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, + chip, &ops)) < 0) { snd_ca0106_free(chip); return err; } @@ -1683,7 +1629,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, static int dev; struct snd_card *card; struct snd_ca0106 *chip; - int i, err; + int err; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -1696,30 +1642,44 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, if (card == NULL) return -ENOMEM; - err = snd_ca0106_create(dev, card, pci, &chip); - if (err < 0) - goto error; - - for (i = 0; i < 4; i++) { - err = snd_ca0106_pcm(chip, i); - if (err < 0) - goto error; + if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { + snd_card_free(card); + return err; } - if (chip->details->ac97 == 1) { - /* The SB0410 and SB0413 do not have an AC97 chip. */ - err = snd_ca0106_ac97(chip); - if (err < 0) - goto error; + if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { + snd_card_free(card); + return err; + } + if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ + if ((err = snd_ca0106_ac97(chip)) < 0) { + snd_card_free(card); + return err; + } + } + if ((err = snd_ca0106_mixer(chip)) < 0) { + snd_card_free(card); + return err; } - err = snd_ca0106_mixer(chip); - if (err < 0) - goto error; snd_printdd("ca0106: probe for MIDI channel A ..."); - err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); - if (err < 0) - goto error; + if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { + snd_card_free(card); + snd_printdd(" failed, err=0x%x\n",err); + return err; + } snd_printdd(" done.\n"); #ifdef CONFIG_PROC_FS @@ -1728,17 +1688,14 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_card_set_dev(card, &pci->dev); - err = snd_card_register(card); - if (err < 0) - goto error; + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } pci_set_drvdata(pci, card); dev++; return 0; - - error: - snd_card_free(card); - return err; } static void __devexit snd_ca0106_remove(struct pci_dev *pci) @@ -1747,52 +1704,6 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -#ifdef CONFIG_PM -static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) -{ - struct snd_card *card = pci_get_drvdata(pci); - struct snd_ca0106 *chip = card->private_data; - int i; - - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < 4; i++) - snd_pcm_suspend_all(chip->pcm[i]); - snd_ac97_suspend(chip->ac97); - snd_ca0106_mixer_suspend(chip); - - ca0106_stop_chip(chip); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, pci_choose_state(pci, state)); - return 0; -} - -static int snd_ca0106_resume(struct pci_dev *pci) -{ - struct snd_card *card = pci_get_drvdata(pci); - struct snd_ca0106 *chip = card->private_data; - int i; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - pci_enable_device(pci); - pci_set_master(pci); - - ca0106_init_chip(chip); - - snd_ac97_resume(chip->ac97); - snd_ca0106_mixer_resume(chip); - if (chip->details->spi_dac) { - for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) - snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]); - } - - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - return 0; -} -#endif - // PCI IDs static struct pci_device_id snd_ca0106_ids[] = { { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ @@ -1806,10 +1717,6 @@ static struct pci_driver driver = { .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), -#ifdef CONFIG_PM - .suspend = snd_ca0106_suspend, - .resume = snd_ca0106_resume, -#endif }; // initialization of the module diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index cccc32cdb943..3025ed1b6e1e 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -75,84 +75,6 @@ #include "ca0106.h" -static void ca0106_spdif_enable(struct snd_ca0106 *emu) -{ - unsigned int val; - - if (emu->spdif_enable) { - /* Digital */ - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); - val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); - val = inl(emu->port + GPIO) & ~0x101; - outl(val, emu->port + GPIO); - - } else { - /* Analog */ - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); - val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); - val = inl(emu->port + GPIO) | 0x101; - outl(val, emu->port + GPIO); - } -} - -static void ca0106_set_capture_source(struct snd_ca0106 *emu) -{ - unsigned int val = emu->capture_source; - unsigned int source, mask; - source = (val << 28) | (val << 24) | (val << 20) | (val << 16); - mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; - snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); -} - -static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu, - unsigned int val, int force) -{ - unsigned int ngain, ogain; - u32 source; - - snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - ngain = emu->i2c_capture_volume[val][0]; /* Left */ - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ - if (force || ngain != ogain) - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff); - ngain = emu->i2c_capture_volume[val][1]; /* Right */ - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ - if (force || ngain != ogain) - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff); - source = 1 << val; - snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ - emu->i2c_capture_source = val; -} - -static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) -{ - u32 tmp; - - if (emu->capture_mic_line_in) { - /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; - tmp = tmp | 0x400; - outl(tmp, emu->port+GPIO); - /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ - } else { - /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; - outl(tmp, emu->port+GPIO); - /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ - } -} - -static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) -{ - snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); -} - -/* - */ static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); @@ -173,12 +95,30 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; + u32 mask; val = !!ucontrol->value.integer.value[0]; change = (emu->spdif_enable != val); if (change) { emu->spdif_enable = val; - ca0106_spdif_enable(emu); + if (val) { + /* Digital */ + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, + snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); + mask = inl(emu->port + GPIO) & ~0x101; + outl(mask, emu->port + GPIO); + + } else { + /* Analog */ + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, + snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); + mask = inl(emu->port + GPIO) | 0x101; + outl(mask, emu->port + GPIO); + } } return change; } @@ -214,6 +154,8 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; + u32 mask; + u32 source; val = ucontrol->value.enumerated.item[0] ; if (val >= 6) @@ -221,7 +163,9 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, change = (emu->capture_source != val); if (change) { emu->capture_source = val; - ca0106_set_capture_source(emu); + source = (val << 28) | (val << 24) | (val << 20) | (val << 16); + mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; + snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); } return change; } @@ -256,7 +200,9 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, { struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int source_id; + unsigned int ngain, ogain; int change = 0; + u32 source; /* If the capture source has changed, * update the capture volume from the cached value * for the particular source. @@ -266,7 +212,18 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, return -EINVAL; change = (emu->i2c_capture_source != source_id); if (change) { - ca0106_set_i2c_capture_source(emu, source_id, 0); + snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ + if (ngain != ogain) + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); + ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ + if (ngain != ogain) + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); + source = 1 << source_id; + snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ + emu->i2c_capture_source = source_id; } return change; } @@ -314,6 +271,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; + u32 tmp; val = ucontrol->value.enumerated.item[0] ; if (val > 1) @@ -321,7 +279,18 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, change = (emu->capture_mic_line_in != val); if (change) { emu->capture_mic_line_in = val; - ca0106_set_capture_mic_line_in(emu); + if (val) { + //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + tmp = tmp | 0x400; + outl(tmp, emu->port+GPIO); + //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); + } else { + //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + outl(tmp, emu->port+GPIO); + //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); + } } return change; } @@ -390,8 +359,8 @@ static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, (ucontrol->value.iec958.status[3] << 24); change = val != emu->spdif_bits[idx]; if (change) { + snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); emu->spdif_bits[idx] = val; - ca0106_set_spdif_bits(emu, idx); } return change; } @@ -804,50 +773,3 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) return 0; } -#ifdef CONFIG_PM -struct ca0106_vol_tbl { - unsigned int reg; - unsigned int channel_id; -}; - -static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { - { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 }, - { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 }, - { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 }, - { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 }, - { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 }, - { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 }, - { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 }, - { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 }, - { 1, CAPTURE_CONTROL }, -}; - -void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip) -{ - int i; - - /* save volumes */ - for (i = 0; i < NUM_SAVED_VOLUMES; i++) - chip->saved_vol[i] = - snd_ca0106_ptr_read(chip, saved_volumes[i].reg, - saved_volumes[i].channel_id); -} - -void snd_ca0106_mixer_resume(struct snd_ca0106 *chip) -{ - int i; - - for (i = 0; i < NUM_SAVED_VOLUMES; i++) - snd_ca0106_ptr_write(chip, saved_volumes[i].reg, - saved_volumes[i].channel_id, - chip->saved_vol[i]); - - ca0106_spdif_enable(chip); - ca0106_set_capture_source(chip); - ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1); - for (i = 0; i < 4; i++) - ca0106_set_spdif_bits(chip, i); - if (chip->details->i2c_adc) - ca0106_set_capture_mic_line_in(chip); -} -#endif /* CONFIG_PM */ diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 8ab07aa63652..fb6dc3980257 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3640,10 +3640,7 @@ int snd_cs46xx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct snd_cs46xx *chip = card->private_data; - int amp_saved; -#ifdef CONFIG_SND_CS46XX_NEW_DSP - int i; -#endif + int i, amp_saved; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 7958006a1d66..de5ee8f097f6 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -69,7 +69,7 @@ MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); * EMU10K1 init / done *************************************************************************/ -void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch) +void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch) { snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); snd_emu10k1_ptr_write(emu, IP, ch, 0); @@ -151,9 +151,9 @@ static unsigned int i2c_adc_init[][2] = { { 0x12, 0x32 }, /* ALC Control 3 */ { 0x13, 0x00 }, /* Noise gate control */ { 0x14, 0xa6 }, /* Limiter control */ - { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for A2ZS Notebook */ + { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ }; - + static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) { unsigned int silent_page; @@ -161,8 +161,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) u32 tmp; /* disable audio and lock cache */ - outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | - HCFG_MUTEBUTTONENABLE, emu->port + HCFG); + outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, + emu->port + HCFG); /* reset recording buffers */ snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); @@ -179,7 +179,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); - if (emu->audigy) { + if (emu->audigy){ /* set SPDIF bypass mode */ snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT); /* enable rear left + rear right AC97 slots */ @@ -197,12 +197,12 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ - /* Setup SRCMulti_I2S SamplingRate */ + //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); - + /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14); /* Setup SRCMulti Input Audio Enable */ @@ -217,7 +217,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); - /* Setup SRCMulti_I2S SamplingRate */ + //Setup SRCMulti_I2S SamplingRate tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); @@ -270,13 +270,13 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) size = ARRAY_SIZE(i2c_adc_init); for (n = 0; n < size; n++) snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); - for (n = 0; n < 4; n++) { - emu->i2c_capture_volume[n][0] = 0xcf; - emu->i2c_capture_volume[n][1] = 0xcf; + for (n=0; n < 4; n++) { + emu->i2c_capture_volume[n][0]= 0xcf; + emu->i2c_capture_volume[n][1]= 0xcf; } } - + snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ @@ -313,7 +313,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) (emu->model == 0x21 && emu->revision < 6)) outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG); else - /* With on-chip joystick */ + // With on-chip joystick outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); if (enable_ir) { /* enable IR for SB Live */ @@ -335,9 +335,9 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG); udelay(100); outl(reg, emu->port + HCFG); - } + } } - + if (emu->card_capabilities->emu_model) { ; /* Disable all access to A_IOCFG for the emu1010 */ } else if (emu->card_capabilities->i2c_adc) { @@ -364,7 +364,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); - + if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Unmute Analog now. Set GPO6 to 1 for Apollo. * This has to be done after init ALice3 I2SOut beyond 48KHz. @@ -378,12 +378,12 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); } } - + #if 0 { unsigned int tmp; /* FIXME: the following routine disables LiveDrive-II !! */ - /* TOSLink detection */ + // TOSLink detection emu->tos_link = 0; tmp = inl(emu->port + HCFG); if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { @@ -400,7 +400,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); } -int snd_emu10k1_done(struct snd_emu10k1 *emu) +int snd_emu10k1_done(struct snd_emu10k1 * emu) { int ch; @@ -495,7 +495,7 @@ int snd_emu10k1_done(struct snd_emu10k1 *emu) #define EC_LAST_PROMFILE_ADDR 0x2f -#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The +#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The * can be up to 30 characters in length * and is stored as a NULL-terminated * ASCII string. Any unused bytes must be @@ -503,8 +503,8 @@ int snd_emu10k1_done(struct snd_emu10k1 *emu) #define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */ -/* Most of this stuff is pretty self-evident. According to the hardware - * dudes, we need to leave the ADCCAL bit low in order to avoid a DC +/* Most of this stuff is pretty self-evident. According to the hardware + * dudes, we need to leave the ADCCAL bit low in order to avoid a DC * offset problem. Weird. */ #define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \ @@ -523,7 +523,7 @@ int snd_emu10k1_done(struct snd_emu10k1 *emu) * register. */ -static void snd_emu10k1_ecard_write(struct snd_emu10k1 *emu, unsigned int value) +static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value) { unsigned short count; unsigned int data; @@ -561,7 +561,7 @@ static void snd_emu10k1_ecard_write(struct snd_emu10k1 *emu, unsigned int value) * channel. */ -static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu, +static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu, unsigned short gain) { unsigned int bit; @@ -574,7 +574,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu, for (bit = (1 << 15); bit; bit >>= 1) { unsigned int value; - + value = emu->ecard_ctrl & ~(EC_TRIM_CSN | EC_TRIM_SDATA); if (gain & bit) @@ -589,7 +589,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu, snd_emu10k1_ecard_write(emu, emu->ecard_ctrl); } -static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu) +static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu) { unsigned int hc_value; @@ -598,7 +598,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu) EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) | EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL); - /* Step 0: Set the codec type in the hardware control register + /* Step 0: Set the codec type in the hardware control register * and enable audio output */ hc_value = inl(emu->port + HCFG); outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG); @@ -629,7 +629,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu) return 0; } -static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) +static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) { unsigned long special_port; unsigned int value; @@ -656,7 +656,7 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) return 0; } -static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filename) +static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * filename) { int err; int n, i; @@ -666,12 +666,11 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filena unsigned long flags; const struct firmware *fw_entry; - err = request_firmware(&fw_entry, filename, &emu->pci->dev); - if (err != 0) { - snd_printk(KERN_ERR "firmware: %s not found. Err = %d\n", filename, err); + if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { + snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); return err; } - snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size); + snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); /* The FPGA is a Xilinx Spartan IIE XC2S50E */ /* GPIO7 -> FPGA PGMN @@ -686,13 +685,13 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filena outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ write_post = inl(emu->port + A_IOCFG); udelay(100); /* Allow FPGA memory to clean */ - for (n = 0; n < fw_entry->size; n++) { - value = fw_entry->data[n]; - for (i = 0; i < 8; i++) { + for(n = 0; n < fw_entry->size; n++) { + value=fw_entry->data[n]; + for(i = 0; i < 8; i++) { reg = 0x80; if (value & 0x1) reg = reg | 0x20; - value = value >> 1; + value = value >> 1; outl(reg, emu->port + A_IOCFG); write_post = inl(emu->port + A_IOCFG); outl(reg | 0x40, emu->port + A_IOCFG); @@ -704,14 +703,14 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filena write_post = inl(emu->port + A_IOCFG); spin_unlock_irqrestore(&emu->emu_lock, flags); - release_firmware(fw_entry); + release_firmware(fw_entry); return 0; } static int emu1010_firmware_thread(void *data) { - struct snd_emu10k1 *emu = data; - int tmp, tmp2; + struct snd_emu10k1 * emu = data; + int tmp,tmp2; int reg; int err; @@ -720,50 +719,50 @@ static int emu1010_firmware_thread(void *data) msleep_interruptible(1000); if (kthread_should_stop()) break; - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { /* Audio Dock attached */ /* Return to Audio Dock programming mode */ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { - err = snd_emu1010_load_firmware(emu, DOCK_FILENAME); - if (err != 0) + if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { continue; + } } else if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010B) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) + if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { continue; + } } else if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) + if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { continue; + } } - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); if ((reg & 0x1f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg); + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); continue; } snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); - snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); - snd_printk("Audio Dock ver:%d.%d\n", tmp, tmp2); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); + snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); /* Sync clocking between 1010 and Dock */ /* Allow DLL to settle */ msleep(10); /* Unmute all. Default is muted after a firmware load */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); } } snd_printk(KERN_INFO "emu1010: firmware thread stopping\n"); @@ -801,10 +800,10 @@ static int emu1010_firmware_thread(void *data) * 16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops * 16 x 32-bit capture - snd_emu10k1_capture_efx_ops */ -static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) +static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) { unsigned int i; - int tmp, tmp2; + int tmp,tmp2; int reg; int err; const char *filename = NULL; @@ -819,7 +818,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) * Lock Tank Memory Cache, * Mute all codecs. */ - outl(0x0005a004, emu->port + HCFG); + outl(0x0005a004, emu->port + HCFG); /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, * Mute all codecs. */ @@ -830,25 +829,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) outl(0x0005a000, emu->port + HCFG); /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - snd_printdd("reg1 = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg1=0x%x\n",reg); if ((reg & 0x3f) == 0x15) { /* FPGA netlist already present so clear it */ /* Return to programming mode */ - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 ); } - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - snd_printdd("reg2 = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printdd("reg2=0x%x\n",reg); if ((reg & 0x3f) == 0x15) { /* FPGA failed to return to programming mode */ snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n"); return -ENODEV; } - snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg); + snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); switch (emu->card_capabilities->emu_model) { case EMU_MODEL_EMU1010: filename = HANA_FILENAME; @@ -877,25 +876,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) } /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); if ((reg & 0x3f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg); + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg); return -ENODEV; } snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp); - snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2); - snd_printk("emu1010: Hana version: %d.%d\n", tmp, tmp2); + snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 ); + snd_printk("Hana ver:%d.%d\n",tmp ,tmp2); /* Enable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON ); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); /* Optical -> ADAT I/O */ /* 0 : SPDIF * 1 : ADAT @@ -905,42 +904,41 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) tmp = 0; tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); - snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); /* Set no attenuation on Audio Dock pads. */ - snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00); + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); emu->emu1010.adc_pads = 0x00; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); /* Unmute Audio dock DACs, Headphone source DAC-4. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); - snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); + snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp ); /* DAC PADs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f); + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f ); emu->emu1010.dac_pads = 0x0f; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* MIDI routing */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* Unknown. */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); - /* IRQ Enable: Alll on */ - /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); + /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ /* IRQ Enable: All off */ - snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00); + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); + snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg); /* Default WCLK set to 48kHz. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00); + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 ); /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); - /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); /* Audio Dock LEDs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); #if 0 /* For 96kHz */ @@ -994,7 +992,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) * Defaults only, users will set their own values anyways, let's * just copy/paste. */ - + snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1); snd_emu1010_fpga_link_dst_src_write(emu, @@ -1039,19 +1037,19 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); #endif - for (i = 0; i < 0x20; i++) { - /* AudioDock Elink <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0100 + i, EMU_SRC_SILENCE); + for (i = 0;i < 0x20; i++ ) { + /* AudioDock Elink <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE); } - for (i = 0; i < 4; i++) { + for (i = 0;i < 4; i++) { /* Hana SPDIF Out <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0200 + i, EMU_SRC_SILENCE); + snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE); } - for (i = 0; i < 7; i++) { + for (i = 0;i < 7; i++) { /* Hamoa DAC <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0300 + i, EMU_SRC_SILENCE); + snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE); } - for (i = 0; i < 7; i++) { + for (i = 0;i < 7; i++) { /* Hana ADAT Out <- Silence */ snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); } @@ -1067,30 +1065,30 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01); /* Unmute all */ - - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, * Lock Sound Memory Cache, Lock Tank Memory Cache, * Mute all codecs. */ - outl(0x0000a000, emu->port + HCFG); + outl(0x0000a000, emu->port + HCFG); /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, * Lock Sound Memory Cache, Lock Tank Memory Cache, * Un-Mute all codecs. */ outl(0x0000a001, emu->port + HCFG); - + /* Initial boot complete. Now patches */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ /* Start Micro/Audio Dock firmware loader thread */ if (!emu->emu1010.firmware_thread) { @@ -1220,20 +1218,20 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) emu->emu1010.output_source[23] = 28; } /* TEMP: Select SPDIF in/out */ - /* snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); */ /* Output spdif */ + //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ /* TEMP: Select 48kHz SPDIF out */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); - /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); + //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); emu->emu1010.internal_clock = 1; /* 48000 */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ - /* snd_emu1010_fpga_write(emu, 0x7, 0x0); */ /* Mute all */ - /* snd_emu1010_fpga_write(emu, 0x7, 0x1); */ /* Unmute all */ - /* snd_emu1010_fpga_write(emu, 0xe, 0x12); */ /* Set LEDs on Audio Dock */ + //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ + //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */ + //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */ return 0; } @@ -1249,13 +1247,13 @@ static void free_pm_buffer(struct snd_emu10k1 *emu); static int snd_emu10k1_free(struct snd_emu10k1 *emu) { if (emu->port) { /* avoid access to already used hardware */ - snd_emu10k1_fx8010_tram_setup(emu, 0); + snd_emu10k1_fx8010_tram_setup(emu, 0); snd_emu10k1_done(emu); snd_emu10k1_free_efx(emu); - } + } if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); } if (emu->emu1010.firmware_thread) kthread_stop(emu->emu1010.firmware_thread); @@ -1280,7 +1278,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) #endif if (emu->port) pci_release_regions(emu->pci); - if (emu->card_capabilities->ca0151_chip) /* P16V */ + if (emu->card_capabilities->ca0151_chip) /* P16V */ snd_p16v_free(emu); pci_disable_device(emu->pci); kfree(emu); @@ -1294,6 +1292,21 @@ static int snd_emu10k1_dev_free(struct snd_device *device) } static struct snd_emu_chip_details emu_chip_details[] = { + /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ + /* Tested by James@superbug.co.uk 3rd July 2005 */ + /* DSP: CA0108-IAT + * DAC: CS4382-KQ + * ADC: Philips 1361T + * AC97: STAC9750 + * CA0151: None + */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, + .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0108_chip = 1, + .spk71 = 1, + .ac97_chip = 1} , /* Audigy4 (Not PRO) SB0610 */ /* Tested by James@superbug.co.uk 4th April 2006 */ /* A_IOCFG bits @@ -1333,37 +1346,20 @@ static struct snd_emu_chip_details emu_chip_details[] = { * CA0151: None */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, - .driver = "Audigy2", .name = "SB Audigy 4 [SB0610]", + .driver = "Audigy2", .name = "Audigy 4 [SB0610]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , - /* Audigy 2 Value AC3 out does not work yet. - * Need to find out how to turn off interpolators. - */ - /* Tested by James@superbug.co.uk 3rd July 2005 */ - /* DSP: CA0108-IAT - * DAC: CS4382-KQ - * ADC: Philips 1361T - * AC97: STAC9750 - * CA0151: None - */ - {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, - .driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]", - .id = "Audigy2", - .emu10k2_chip = 1, - .ca0108_chip = 1, - .spk71 = 1, - .ac97_chip = 1} , /* Audigy 2 ZS Notebook Cardbus card.*/ /* Tested by James@superbug.co.uk 6th November 2006 */ /* Audio output 7.1/Headphones working. * Digital output working. (AC3 not checked, only PCM) * Audio Mic/Line inputs working. * Digital input not tested. - */ + */ /* DSP: Tina2 * DAC: Wolfson WM8768/WM8568 * ADC: Wolfson WM8775 @@ -1390,7 +1386,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, - .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]", + .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1400,7 +1396,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1} , /* Tested by James@superbug.co.uk 4th Nov 2007. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, - .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", + .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1408,49 +1404,47 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1 , .emu_model = EMU_MODEL_EMU1616}, /* Tested by James@superbug.co.uk 4th Nov 2007. */ - /* This is MAEM8960, 0202 is MAEM 8980 */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, - .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]", + .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */ + .emu_model = EMU_MODEL_EMU1010B}, /* Tested by James@superbug.co.uk 8th July 2005. */ - /* This is MAEM8810, 0202 is MAEM8820 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, - .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]", + .driver = "Audigy2", .name = "E-mu 1010 [4001]", .id = "EMU1010", .emu10k2_chip = 1, .ca0102_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */ + .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */ /* EMU0404b */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]", + .driver = "Audigy2", .name = "E-mu 0404b [4002]", .id = "EMU0404", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */ + .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ /* Tested by James@superbug.co.uk 20-3-2007. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]", + .driver = "Audigy2", .name = "E-mu 0404 [4002]", .id = "EMU0404", .emu10k2_chip = 1, .ca0102_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ - /* Note that all E-mu cards require kernel 2.6 or newer. */ - {.vendor = 0x1102, .device = 0x0008, - .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", + /* Audigy4 (Not PRO) SB0610 */ + {.vendor = 0x1102, .device = 0x0008, + .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .ac97_chip = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, - .driver = "Audigy2", .name = "SB Audigy 4 PRO [SB0380]", + .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1463,7 +1457,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * Just like 0x20021102 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20061102, - .driver = "Audigy2", .name = "SB Audigy 2 [SB0350b]", + .driver = "Audigy2", .name = "Audigy 2 [SB0350b]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1473,7 +1467,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, - .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350]", + .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1483,7 +1477,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, - .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0360]", + .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1501,7 +1495,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * CA0151: Yes */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, - .driver = "Audigy2", .name = "SB Audigy 2 [SB0240]", + .driver = "Audigy2", .name = "Audigy 2 [SB0240]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1511,7 +1505,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, - .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]", + .driver = "Audigy2", .name = "Audigy 2 EX [1005]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1521,7 +1515,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { /* Dell OEM/Creative Labs Audigy 2 ZS */ /* See ALSA bug#1365 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10031102, - .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0353]", + .driver = "Audigy2", .name = "Audigy 2 ZS [SB0353]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1530,7 +1524,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, - .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]", + .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1541,7 +1535,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, - .driver = "Audigy2", .name = "SB Audigy 2 [Unknown]", + .driver = "Audigy2", .name = "Audigy 2 [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1549,79 +1543,78 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102, - .driver = "Audigy", .name = "SB Audigy 1 [SB0092]", + .driver = "Audigy", .name = "Audigy 1 [SB0090]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102, - .driver = "Audigy", .name = "SB Audigy 1 ES [SB0160]", + .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102, - .driver = "Audigy", .name = "SB Audigy 1 [SB0090]", + .driver = "Audigy", .name = "Audigy 1 [SB0090]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, - .driver = "Audigy", .name = "Audigy 1 [Unknown]", + .driver = "Audigy", .name = "Audigy 1 [Unknown]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102, - .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]", - .id = "Live", - .emu10k1_chip = 1, - .ac97_chip = 1, - .sblive51 = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806b1102, - .driver = "EMU10K1", .name = "SB Live! [SB0105]", + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102, + .driver = "EMU10K1", .name = "SBLive! [SB0105]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806a1102, - .driver = "EMU10K1", .name = "SB Live! Value [SB0103]", + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102, + .driver = "EMU10K1", .name = "SBLive! Value [SB0103]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102, - .driver = "EMU10K1", .name = "SB Live! Value [SB0101]", + .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by ALSA bug#1680 26th December 2005 */ - /* note: It really has SB0220 written on the card, */ - /* but it's SB0228 according to kx.inf */ + /* note: It really has SB0220 written on the card. */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80661102, - .driver = "EMU10K1", .name = "SB Live! 5.1 Dell OEM [SB0228]", + .driver = "EMU10K1", .name = "SB Live 5.1 Dell OEM [SB0220]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by Thomas Zehetbauer 27th Aug 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102, - .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]", + .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102, + .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, - .driver = "EMU10K1", .name = "SB Live! 5.1", + .driver = "EMU10K1", .name = "SB Live 5.1", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by alsa bugtrack user "hus" bug #1297 12th Aug 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, - .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0060]", + .driver = "EMU10K1", .name = "SBLive 5.1 [SB0060]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 2, /* ac97 is optional; both SBLive 5.1 and platinum @@ -1629,78 +1622,78 @@ static struct snd_emu_chip_details emu_chip_details[] = { */ .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4850]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, - .driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]", + .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4871]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4831]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4870]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4832]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4830]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102, - .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", + .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4780]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, - .driver = "EMU10K1", .name = "E-mu APS [PC545]", + .driver = "EMU10K1", .name = "E-mu APS [4001]", .id = "APS", .emu10k1_chip = 1, .ecard = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102, - .driver = "EMU10K1", .name = "SB Live! [CT4620]", + .driver = "EMU10K1", .name = "SBLive! [CT4620]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102, - .driver = "EMU10K1", .name = "SB Live! Value [CT4670]", + .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, - .driver = "EMU10K1", .name = "SB Live! [Unknown]", + .driver = "EMU10K1", .name = "SB Live [Unknown]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, @@ -1709,13 +1702,13 @@ static struct snd_emu_chip_details emu_chip_details[] = { }; int __devinit snd_emu10k1_create(struct snd_card *card, - struct pci_dev *pci, + struct pci_dev * pci, unsigned short extin_mask, unsigned short extout_mask, long max_cache_bytes, int enable_ir, uint subsystem, - struct snd_emu10k1 **remu) + struct snd_emu10k1 ** remu) { struct snd_emu10k1 *emu; int idx, err; @@ -1725,12 +1718,11 @@ int __devinit snd_emu10k1_create(struct snd_card *card, static struct snd_device_ops ops = { .dev_free = snd_emu10k1_dev_free, }; - + *remu = NULL; /* enable PCI device */ - err = pci_enable_device(pci); - if (err < 0) + if ((err = pci_enable_device(pci)) < 0) return err; emu = kzalloc(sizeof(*emu), GFP_KERNEL); @@ -1757,17 +1749,16 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); - snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model); + snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model); for (c = emu_chip_details; c->vendor; c++) { if (c->vendor == pci->vendor && c->device == pci->device) { if (subsystem) { - if (c->subsystem && (c->subsystem == subsystem)) + if (c->subsystem && (c->subsystem == subsystem) ) { break; - else - continue; + } else continue; } else { - if (c->subsystem && (c->subsystem != emu->serial)) + if (c->subsystem && (c->subsystem != emu->serial) ) continue; if (c->revision && c->revision != emu->revision) continue; @@ -1783,18 +1774,14 @@ int __devinit snd_emu10k1_create(struct snd_card *card, } emu->card_capabilities = c; if (c->subsystem && !subsystem) - snd_printdd("Sound card name = %s\n", c->name); - else if (subsystem) - snd_printdd("Sound card name = %s, " - "vendor = 0x%x, device = 0x%x, subsystem = 0x%x. " - "Forced to subsytem = 0x%x\n", c->name, - pci->vendor, pci->device, emu->serial, c->subsystem); - else - snd_printdd("Sound card name = %s, " - "vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n", - c->name, pci->vendor, pci->device, - emu->serial); - + snd_printdd("Sound card name=%s\n", c->name); + else if (subsystem) + snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x. Forced to subsytem=0x%x\n", + c->name, pci->vendor, pci->device, emu->serial, c->subsystem); + else + snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x.\n", + c->name, pci->vendor, pci->device, emu->serial); + if (!*card->id && c->id) { int i, n = 0; strlcpy(card->id, c->id, sizeof(card->id)); @@ -1828,8 +1815,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, else emu->gpr_base = FXGPREGBASE; - err = pci_request_regions(pci, "EMU10K1"); - if (err < 0) { + if ((err = pci_request_regions(pci, "EMU10K1")) < 0) { kfree(emu); pci_disable_device(pci); return err; @@ -1876,25 +1862,21 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->enable_ir = enable_ir; if (emu->card_capabilities->ca_cardbus_chip) { - err = snd_emu10k1_cardbus_init(emu); - if (err < 0) + if ((err = snd_emu10k1_cardbus_init(emu)) < 0) goto error; } if (emu->card_capabilities->ecard) { - err = snd_emu10k1_ecard_init(emu); - if (err < 0) + if ((err = snd_emu10k1_ecard_init(emu)) < 0) goto error; } else if (emu->card_capabilities->emu_model) { - err = snd_emu10k1_emu1010_init(emu); - if (err < 0) { - snd_emu10k1_free(emu); - return err; - } + if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { + snd_emu10k1_free(emu); + return err; + } } else { /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version does not support this, it shouldn't do any harm */ - snd_emu10k1_ptr_write(emu, AC97SLOT, 0, - AC97SLOT_CNTR|AC97SLOT_LFE); + snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); } /* initialize TRAM setup */ @@ -1934,7 +1916,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, snd_emu10k1_synth_alloc(emu, 4096); if (emu->reserved_page) emu->reserved_page->map_locked = 1; - + /* Clear silent pages and set up pointers */ memset(emu->silent_page.area, 0, PAGE_SIZE); silent_page = emu->silent_page.addr << 1; @@ -1947,23 +1929,19 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->voices[idx].number = idx; } - err = snd_emu10k1_init(emu, enable_ir, 0); - if (err < 0) + if ((err = snd_emu10k1_init(emu, enable_ir, 0)) < 0) goto error; #ifdef CONFIG_PM - err = alloc_pm_buffer(emu); - if (err < 0) + if ((err = alloc_pm_buffer(emu)) < 0) goto error; #endif /* Initialize the effect engine */ - err = snd_emu10k1_init_efx(emu); - if (err < 0) + if ((err = snd_emu10k1_init_efx(emu)) < 0) goto error; snd_emu10k1_audio_enable(emu); - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops); - if (err < 0) + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0) goto error; #ifdef CONFIG_PROC_FS @@ -2003,7 +1981,7 @@ static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu) if (emu->audigy) size += ARRAY_SIZE(saved_regs_audigy); emu->saved_ptr = vmalloc(4 * NUM_G * size); - if (!emu->saved_ptr) + if (! emu->saved_ptr) return -ENOMEM; if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0) return -ENOMEM; @@ -2048,7 +2026,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) if (emu->card_capabilities->ecard) snd_emu10k1_ecard_init(emu); else if (emu->card_capabilities->emu_model) - snd_emu10k1_emu1010_init(emu); + snd_emu10k1_emu1010_init(emu); else snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); snd_emu10k1_init(emu, emu->enable_ir, 1); diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index b0fb6c917c38..f34bbfb705f5 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1639,45 +1639,6 @@ static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = .put = snd_emu10k1_shared_spdif_put }; -/* workaround for too low volume on Audigy due to 16bit/24bit conversion */ - -#define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info - -static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int val; - - /* FIXME: better to use a cached version */ - val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); - ucontrol->value.integer.value[0] = !!val; - return 0; -} - -static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int val; - - if (ucontrol->value.integer.value[0]) - val = 0x0f0f; - else - val = 0; - return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); -} - -static struct snd_kcontrol_new snd_audigy_capture_boost __devinitdata = -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Capture Boost", - .info = snd_audigy_capture_boost_info, - .get = snd_audigy_capture_boost_get, - .put = snd_audigy_capture_boost_put -}; - - /* */ static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) @@ -2126,12 +2087,5 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, } } - if (emu->card_capabilities->ac97_chip && emu->audigy) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, - emu)); - if (err < 0) - return err; - } - return 0; } diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig deleted file mode 100644 index eb2a19b894a0..000000000000 --- a/sound/pci/hda/Kconfig +++ /dev/null @@ -1,188 +0,0 @@ -menuconfig SND_HDA_INTEL - tristate "Intel HD Audio" - select SND_PCM - select SND_VMASTER - select SND_JACK if INPUT=y || INPUT=SND - help - Say Y here to include support for Intel "High Definition - Audio" (Azalia) and its compatible devices. - - This option enables the HD-audio controller. Don't forget - to choose the appropriate codec options below. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-intel. - -if SND_HDA_INTEL - -config SND_HDA_HWDEP - bool "Build hwdep interface for HD-audio driver" - select SND_HWDEP - help - Say Y here to build a hwdep interface for HD-audio driver. - This interface can be used for out-of-band communication - with codecs for debugging purposes. - -config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" - depends on SND_HDA_HWDEP && EXPERIMENTAL - help - Say Y here to enable the HD-audio codec re-configuration feature. - This adds the sysfs interfaces to allow user to clear the whole - codec configuration, change the codec setup, add extra verbs, - and re-configure the codec dynamically. - -config SND_HDA_INPUT_BEEP - bool "Support digital beep via input layer" - depends on INPUT=y || INPUT=SND_HDA_INTEL - help - Say Y here to build a digital beep interface for HD-audio - driver. This interface is used to generate digital beeps. - -config SND_HDA_CODEC_REALTEK - bool "Build Realtek HD-audio codec support" - default y - help - Say Y here to include Realtek HD-audio codec support in - snd-hda-intel driver, such as ALC880. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-realtek. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_ANALOG - bool "Build Analog Device HD-audio codec support" - default y - help - Say Y here to include Analog Device HD-audio codec support in - snd-hda-intel driver, such as AD1986A. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-analog. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_SIGMATEL - bool "Build IDT/Sigmatel HD-audio codec support" - default y - help - Say Y here to include IDT (Sigmatel) HD-audio codec support in - snd-hda-intel driver, such as STAC9200. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-idt. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_VIA - bool "Build VIA HD-audio codec support" - default y - help - Say Y here to include VIA HD-audio codec support in - snd-hda-intel driver, such as VT1708. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-via. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_ATIHDMI - bool "Build ATI HDMI HD-audio codec support" - default y - help - Say Y here to include ATI HDMI HD-audio codec support in - snd-hda-intel driver, such as ATI RS600 HDMI. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-atihdmi. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_NVHDMI - bool "Build NVIDIA HDMI HD-audio codec support" - default y - help - Say Y here to include NVIDIA HDMI HD-audio codec support in - snd-hda-intel driver, such as NVIDIA MCP78 HDMI. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-nvhdmi. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_INTELHDMI - bool "Build INTEL HDMI HD-audio codec support" - default y - help - Say Y here to include INTEL HDMI HD-audio codec support in - snd-hda-intel driver, such as Eaglelake integrated HDMI. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-intelhdmi. - This module is automatically loaded at probing. - -config SND_HDA_ELD - def_bool y - depends on SND_HDA_CODEC_INTELHDMI - -config SND_HDA_CODEC_CONEXANT - bool "Build Conexant HD-audio codec support" - default y - help - Say Y here to include Conexant HD-audio codec support in - snd-hda-intel driver, such as CX20549. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-conexant. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_CMEDIA - bool "Build C-Media HD-audio codec support" - default y - help - Say Y here to include C-Media HD-audio codec support in - snd-hda-intel driver, such as CMI9880. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-cmedia. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_SI3054 - bool "Build Silicon Labs 3054 HD-modem codec support" - default y - help - Say Y here to include Silicon Labs 3054 HD-modem codec - (and compatibles) support in snd-hda-intel driver. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-si3054. - This module is automatically loaded at probing. - -config SND_HDA_GENERIC - bool "Enable generic HD-audio codec parser" - default y - help - Say Y here to enable the generic HD-audio codec parser - in snd-hda-intel driver. - -config SND_HDA_POWER_SAVE - bool "Aggressive power-saving on HD-audio" - help - Say Y here to enable more aggressive power-saving mode on - HD-audio driver. The power-saving timeout can be configured - via power_save option or over sysfs on-the-fly. - -config SND_HDA_POWER_SAVE_DEFAULT - int "Default time-out for HD-audio power-save mode" - depends on SND_HDA_POWER_SAVE - default 0 - help - The default time-out value in seconds for HD-audio automatic - power-save mode. 0 means to disable the power-save mode. - -endif diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 50f9d0967251..1980c6d207e7 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,59 +1,20 @@ -snd-hda-intel-objs := hda_intel.o +snd-hda-intel-y := hda_intel.o +# since snd-hda-intel is the only driver using hda-codec, +# merge it into a single module although it was originally +# designed to be individual modules +snd-hda-intel-y += hda_codec.o +snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o +snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o +snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o +snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o -snd-hda-codec-y := hda_codec.o -snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o -snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o -# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o -snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o -snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o - -snd-hda-codec-realtek-objs := patch_realtek.o -snd-hda-codec-cmedia-objs := patch_cmedia.o -snd-hda-codec-analog-objs := patch_analog.o -snd-hda-codec-idt-objs := patch_sigmatel.o -snd-hda-codec-si3054-objs := patch_si3054.o -snd-hda-codec-atihdmi-objs := patch_atihdmi.o -snd-hda-codec-conexant-objs := patch_conexant.o -snd-hda-codec-via-objs := patch_via.o -snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o -snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o hda_eld.o - -# common driver -obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o - -# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans) -ifdef CONFIG_SND_HDA_CODEC_REALTEK -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o -endif -ifdef CONFIG_SND_HDA_CODEC_CMEDIA -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o -endif -ifdef CONFIG_SND_HDA_CODEC_ANALOG -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o -endif -ifdef CONFIG_SND_HDA_CODEC_SIGMATEL -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o -endif -ifdef CONFIG_SND_HDA_CODEC_SI3054 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o -endif -ifdef CONFIG_SND_HDA_CODEC_ATIHDMI -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o -endif -ifdef CONFIG_SND_HDA_CODEC_CONEXANT -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o -endif -ifdef CONFIG_SND_HDA_CODEC_VIA -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o -endif -ifdef CONFIG_SND_HDA_CODEC_NVHDMI -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o -endif -ifdef CONFIG_SND_HDA_CODEC_INTELHDMI -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o -endif - -# this must be the last entry after codec drivers; -# otherwise the codec patches won't be hooked before the PCI probe -# when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e00421c0d8ba..3ecd7e797dee 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -128,7 +128,6 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); void snd_hda_detach_beep_device(struct hda_codec *codec) { @@ -141,4 +140,3 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) kfree(beep); } } -EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d49d0b698687..eb9164176dab 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -31,6 +31,15 @@ #include <sound/initval.h> #include "hda_local.h" #include <sound/hda_hwdep.h> +#include "hda_patch.h" /* codec presets */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* define this option here to hide as static */ +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +module_param(power_save, int, 0644); +MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " + "(in second, 0 = disable)."); +#endif /* * vendor / preset table @@ -61,26 +70,36 @@ static struct hda_vendor_id hda_vendor_ids[] = { {} /* terminator */ }; -static DEFINE_MUTEX(preset_mutex); -static LIST_HEAD(hda_preset_tables); - -int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) -{ - mutex_lock(&preset_mutex); - list_add_tail(&preset->list, &hda_preset_tables); - mutex_unlock(&preset_mutex); - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_add_codec_preset); - -int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) -{ - mutex_lock(&preset_mutex); - list_del(&preset->list); - mutex_unlock(&preset_mutex); - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); +static const struct hda_codec_preset *hda_preset_tables[] = { +#ifdef CONFIG_SND_HDA_CODEC_REALTEK + snd_hda_preset_realtek, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CMEDIA + snd_hda_preset_cmedia, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ANALOG + snd_hda_preset_analog, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL + snd_hda_preset_sigmatel, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SI3054 + snd_hda_preset_si3054, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI + snd_hda_preset_atihdmi, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CONEXANT + snd_hda_preset_conexant, +#endif +#ifdef CONFIG_SND_HDA_CODEC_VIA + snd_hda_preset_via, +#endif +#ifdef CONFIG_SND_HDA_CODEC_NVHDMI + snd_hda_preset_nvhdmi, +#endif + NULL +}; #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_power_work(struct work_struct *work); @@ -89,72 +108,6 @@ static void hda_keep_power_on(struct hda_codec *codec); static inline void hda_keep_power_on(struct hda_codec *codec) {} #endif -const char *snd_hda_get_jack_location(u32 cfg) -{ - static char *bases[7] = { - "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", - }; - static unsigned char specials_idx[] = { - 0x07, 0x08, - 0x17, 0x18, 0x19, - 0x37, 0x38 - }; - static char *specials[] = { - "Rear Panel", "Drive Bar", - "Riser", "HDMI", "ATAPI", - "Mobile-In", "Mobile-Out" - }; - int i; - cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; - if ((cfg & 0x0f) < 7) - return bases[cfg & 0x0f]; - for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { - if (cfg == specials_idx[i]) - return specials[i]; - } - return "UNKNOWN"; -} -EXPORT_SYMBOL_HDA(snd_hda_get_jack_location); - -const char *snd_hda_get_jack_connectivity(u32 cfg) -{ - static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; - - return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; -} -EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity); - -const char *snd_hda_get_jack_type(u32 cfg) -{ - static char *jack_types[16] = { - "Line Out", "Speaker", "HP Out", "CD", - "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", - "Line In", "Aux", "Mic", "Telephony", - "SPDIF In", "Digitial In", "Reserved", "Other" - }; - - return jack_types[(cfg & AC_DEFCFG_DEVICE) - >> AC_DEFCFG_DEVICE_SHIFT]; -} -EXPORT_SYMBOL_HDA(snd_hda_get_jack_type); - -/* - * Compose a 32bit command word to be sent to the HD-audio controller - */ -static inline unsigned int -make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm) -{ - u32 val; - - val = (u32)(codec->addr & 0x0f) << 28; - val |= (u32)direct << 27; - val |= (u32)nid << 20; - val |= verb << 8; - val |= parm; - return val; -} - /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -171,21 +124,17 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - struct hda_bus *bus = codec->bus; unsigned int res; - - res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&bus->cmd_mutex); - if (!bus->ops.command(bus, res)) - res = bus->ops.get_response(bus); + mutex_lock(&codec->bus->cmd_mutex); + if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) + res = codec->bus->ops.get_response(codec); else res = (unsigned int)-1; - mutex_unlock(&bus->cmd_mutex); + mutex_unlock(&codec->bus->cmd_mutex); snd_hda_power_down(codec); return res; } -EXPORT_SYMBOL_HDA(snd_hda_codec_read); /** * snd_hda_codec_write - send a single command without waiting for response @@ -202,19 +151,14 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read); int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - struct hda_bus *bus = codec->bus; - unsigned int res; int err; - - res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&bus->cmd_mutex); - err = bus->ops.command(bus, res); - mutex_unlock(&bus->cmd_mutex); + mutex_lock(&codec->bus->cmd_mutex); + err = codec->bus->ops.command(codec, nid, direct, verb, parm); + mutex_unlock(&codec->bus->cmd_mutex); snd_hda_power_down(codec); return err; } -EXPORT_SYMBOL_HDA(snd_hda_codec_write); /** * snd_hda_sequence_write - sequence writes @@ -229,7 +173,6 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) for (; seq->nid; seq++) snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_HDA(snd_hda_sequence_write); /** * snd_hda_get_sub_nodes - get the range of sub nodes @@ -251,7 +194,6 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } -EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); /** * snd_hda_get_connections - get connection list @@ -340,7 +282,6 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } -EXPORT_SYMBOL_HDA(snd_hda_get_connections); /** @@ -375,7 +316,6 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) return 0; } -EXPORT_SYMBOL_HDA(snd_hda_queue_unsol_event); /* * process queued unsolicited events @@ -405,7 +345,7 @@ static void process_unsol_events(struct work_struct *work) /* * initialize unsolicited queue */ -static int init_unsol_queue(struct hda_bus *bus) +static int __devinit init_unsol_queue(struct hda_bus *bus) { struct hda_bus_unsolicited *unsol; @@ -451,24 +391,9 @@ static int snd_hda_bus_free(struct hda_bus *bus) static int snd_hda_bus_dev_free(struct snd_device *device) { struct hda_bus *bus = device->device_data; - bus->shutdown = 1; return snd_hda_bus_free(bus); } -#ifdef CONFIG_SND_HDA_HWDEP -static int snd_hda_bus_dev_register(struct snd_device *device) -{ - struct hda_bus *bus = device->device_data; - struct hda_codec *codec; - list_for_each_entry(codec, &bus->codec_list, list) { - snd_hda_hwdep_add_sysfs(codec); - } - return 0; -} -#else -#define snd_hda_bus_dev_register NULL -#endif - /** * snd_hda_bus_new - create a HDA bus * @card: the card entry @@ -477,14 +402,13 @@ static int snd_hda_bus_dev_register(struct snd_device *device) * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, +int __devinit snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp) { struct hda_bus *bus; int err; static struct snd_device_ops dev_ops = { - .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, }; @@ -506,7 +430,6 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, bus->private_data = temp->private_data; bus->pci = temp->pci; bus->modelname = temp->modelname; - bus->power_save = temp->power_save; bus->ops = temp->ops; mutex_init(&bus->cmd_mutex); @@ -521,42 +444,27 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, *busp = bus; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_bus_new); #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ - (codec->modelname && !strcmp(codec->modelname, "generic")) + (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) #else #define is_generic_config(codec) 0 #endif -#ifdef MODULE -#define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ -#else -#define HDA_MODREQ_MAX_COUNT 0 /* all presets are statically linked */ -#endif - /* * find a matching codec preset */ -static const struct hda_codec_preset * +static const struct hda_codec_preset __devinit * find_codec_preset(struct hda_codec *codec) { - struct hda_codec_preset_list *tbl; - const struct hda_codec_preset *preset; - int mod_requested = 0; + const struct hda_codec_preset **tbl, *preset; if (is_generic_config(codec)) return NULL; /* use the generic parser */ - again: - mutex_lock(&preset_mutex); - list_for_each_entry(tbl, &hda_preset_tables, list) { - if (!try_module_get(tbl->owner)) { - snd_printk(KERN_ERR "hda_codec: cannot module_get\n"); - continue; - } - for (preset = tbl->preset; preset->id; preset++) { + for (tbl = hda_preset_tables; *tbl; tbl++) { + for (preset = *tbl; preset->id; preset++) { u32 mask = preset->mask; if (preset->afg && preset->afg != codec->afg) continue; @@ -566,40 +474,23 @@ find_codec_preset(struct hda_codec *codec) mask = ~0; if (preset->id == (codec->vendor_id & mask) && (!preset->rev || - preset->rev == codec->revision_id)) { - mutex_unlock(&preset_mutex); - codec->owner = tbl->owner; + preset->rev == codec->revision_id)) return preset; - } } - module_put(tbl->owner); - } - mutex_unlock(&preset_mutex); - - if (mod_requested < HDA_MODREQ_MAX_COUNT) { - char name[32]; - if (!mod_requested) - snprintf(name, sizeof(name), "snd-hda-codec-id:%08x", - codec->vendor_id); - else - snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*", - (codec->vendor_id >> 16) & 0xffff); - request_module(name); - mod_requested++; - goto again; } return NULL; } /* - * get_codec_name - store the codec name + * snd_hda_get_codec_name - store the codec name */ -static int get_codec_name(struct hda_codec *codec) +void snd_hda_get_codec_name(struct hda_codec *codec, + char *name, int namelen) { const struct hda_vendor_id *c; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; - char tmp[16], name[32]; + char tmp[16]; for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { @@ -612,21 +503,16 @@ static int get_codec_name(struct hda_codec *codec) vendor = tmp; } if (codec->preset && codec->preset->name) - snprintf(name, sizeof(name), "%s %s", vendor, - codec->preset->name); + snprintf(name, namelen, "%s %s", vendor, codec->preset->name); else - snprintf(name, sizeof(name), "%s ID %x", vendor, + snprintf(name, namelen, "%s ID %x", vendor, codec->vendor_id & 0xffff); - codec->name = kstrdup(name, GFP_KERNEL); - if (!codec->name) - return -ENOMEM; - return 0; } /* * look for an AFG and MFG nodes */ -static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) +static void __devinit setup_fg_nodes(struct hda_codec *codec) { int i, total_nodes; hda_nid_t nid; @@ -685,15 +571,11 @@ static void snd_hda_codec_free(struct hda_codec *codec) flush_scheduled_work(); #endif list_del(&codec->list); - snd_array_free(&codec->mixers); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); - module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); - kfree(codec->name); - kfree(codec->modelname); kfree(codec->wcaps); kfree(codec); } @@ -706,7 +588,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, +int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp) { struct hda_codec *codec; @@ -735,14 +617,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); - snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); - if (codec->bus->modelname) { - codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); - if (!codec->modelname) { - snd_hda_codec_free(codec); - return -ENODEV; - } - } #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); @@ -788,42 +662,12 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); } - if (bus->modelname) - codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); - - err = snd_hda_codec_configure(codec); - if (err < 0) { - snd_hda_codec_free(codec); - return err; - } - snd_hda_codec_proc_new(codec); - - snd_hda_create_hwdep(codec); - - sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, - codec->subsystem_id, codec->revision_id); - snd_component_add(codec->bus->card, component); - - if (codecp) - *codecp = codec; - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_codec_new); - -int snd_hda_codec_configure(struct hda_codec *codec) -{ - int err; codec->preset = find_codec_preset(codec); - if (!codec->name) { - err = get_codec_name(codec); - if (err < 0) - return err; - } /* audio codec should override the mixer name */ - if (codec->afg || !*codec->bus->card->mixername) - strlcpy(codec->bus->card->mixername, codec->name, - sizeof(codec->bus->card->mixername)); + if (codec->afg || !*bus->card->mixername) + snd_hda_get_codec_name(codec, bus->card->mixername, + sizeof(bus->card->mixername)); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); @@ -840,9 +684,25 @@ int snd_hda_codec_configure(struct hda_codec *codec) printk(KERN_ERR "hda-codec: No codec parser is available\n"); patched: - if (!err && codec->patch_ops.unsol_event) - err = init_unsol_queue(codec->bus); - return err; + if (err < 0) { + snd_hda_codec_free(codec); + return err; + } + + if (codec->patch_ops.unsol_event) + init_unsol_queue(bus); + + snd_hda_codec_proc_new(codec); +#ifdef CONFIG_SND_HDA_HWDEP + snd_hda_create_hwdep(codec); +#endif + + sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); + snd_component_add(codec->bus->card, component); + + if (codecp) + *codecp = codec; + return 0; } /** @@ -868,7 +728,6 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, msleep(1); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); } -EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) { @@ -882,7 +741,6 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); #endif } -EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* * amp access functions @@ -894,17 +752,17 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ -static void /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache, +static void __devinit init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size) { memset(cache, 0, sizeof(*cache)); memset(cache->hash, 0xff, sizeof(cache->hash)); - snd_array_init(&cache->buf, record_size, 64); + cache->record_size = record_size; } static void free_hda_cache(struct hda_cache_rec *cache) { - snd_array_free(&cache->buf); + kfree(cache->buffer); } /* query the hash. allocate an entry if not found. */ @@ -916,17 +774,35 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, struct hda_cache_head *info; while (cur != 0xffff) { - info = snd_array_elem(&cache->buf, cur); + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); if (info->key == key) return info; cur = info->next; } /* add a new hash entry */ - info = snd_array_new(&cache->buf); - if (!info) - return NULL; - cur = snd_array_index(&cache->buf, info); + if (cache->num_entries >= cache->size) { + /* reallocate the array */ + unsigned int new_size = cache->size + 64; + void *new_buffer; + new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); + if (!new_buffer) { + snd_printk(KERN_ERR "hda_codec: " + "can't malloc amp_info\n"); + return NULL; + } + if (cache->buffer) { + memcpy(new_buffer, cache->buffer, + cache->size * cache->record_size); + kfree(cache->buffer); + } + cache->size = new_size; + cache->buffer = new_buffer; + } + cur = cache->num_entries++; + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); info->key = key; info->val = 0; info->next = cache->hash[idx]; @@ -964,7 +840,6 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } return info->amp_caps; } -EXPORT_SYMBOL_HDA(query_amp_caps); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) @@ -978,7 +853,6 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, info->head.val |= INFO_AMP_CAPS; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); /* * read the current volume to info @@ -1032,7 +906,6 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; return get_vol_mute(codec, info, nid, ch, direction, index); } -EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); /* * update the AMP value, mask = bit mask to set, val = the value @@ -1052,7 +925,6 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } -EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); /* * update the AMP stereo with the same mask and value @@ -1066,16 +938,15 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, idx, mask, val); return ret; } -EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); #ifdef SND_HDA_NEEDS_RESUME /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { - struct hda_amp_info *buffer = codec->amp_cache.buf.list; + struct hda_amp_info *buffer = codec->amp_cache.buffer; int i; - for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { + for (i = 0; i < codec->amp_cache.size; i++, buffer++) { u32 key = buffer->head.key; hda_nid_t nid; unsigned int idx, dir, ch; @@ -1092,7 +963,6 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } } -EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ /* volume */ @@ -1120,7 +990,6 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = caps; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1140,7 +1009,6 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, & HDA_AMP_VOLMASK; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1165,7 +1033,6 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put); int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) @@ -1192,7 +1059,6 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv); /* * set (static) TLV for virtual master volume; recalculated as max 0dB @@ -1212,7 +1078,6 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, tlv[2] = -nums * step; tlv[3] = step; } -EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * @@ -1232,67 +1097,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, { return _snd_hda_find_mixer_ctl(codec, name, 0); } -EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); - -/* Add a control element and assign to the codec */ -int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) -{ - int err; - struct snd_kcontrol **knewp; - - err = snd_ctl_add(codec->bus->card, kctl); - if (err < 0) - return err; - knewp = snd_array_new(&codec->mixers); - if (!knewp) - return -ENOMEM; - *knewp = kctl; - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_ctl_add); - -#ifdef CONFIG_SND_HDA_RECONFIG -/* Clear all controls assigned to the given codec */ -void snd_hda_ctls_clear(struct hda_codec *codec) -{ - int i; - struct snd_kcontrol **kctls = codec->mixers.list; - for (i = 0; i < codec->mixers.used; i++) - snd_ctl_remove(codec->bus->card, kctls[i]); - snd_array_free(&codec->mixers); -} - -void snd_hda_codec_reset(struct hda_codec *codec) -{ - int i; - -#ifdef CONFIG_SND_HDA_POWER_SAVE - cancel_delayed_work(&codec->power_work); - flush_scheduled_work(); -#endif - snd_hda_ctls_clear(codec); - /* relase PCMs */ - for (i = 0; i < codec->num_pcms; i++) { - if (codec->pcm_info[i].pcm) { - snd_device_free(codec->bus->card, - codec->pcm_info[i].pcm); - clear_bit(codec->pcm_info[i].device, - codec->bus->pcm_dev_bits); - } - } - if (codec->patch_ops.free) - codec->patch_ops.free(codec); - codec->proc_widget_hook = NULL; - codec->spec = NULL; - free_hda_cache(&codec->amp_cache); - free_hda_cache(&codec->cmd_cache); - codec->num_pcms = 0; - codec->pcm_info = NULL; - codec->preset = NULL; - module_put(codec->owner); - codec->owner = NULL; -} -#endif /* CONFIG_SND_HDA_RECONFIG */ /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, @@ -1311,7 +1115,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) return -ENOMEM; - err = snd_hda_ctl_add(codec, kctl); + err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; @@ -1329,7 +1133,6 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); /* switch */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, @@ -1343,7 +1146,6 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info); int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1363,7 +1165,6 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, HDA_AMP_MUTE) ? 0 : 1; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1394,7 +1195,6 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); /* * bound volume controls @@ -1420,7 +1220,6 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1444,7 +1243,6 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); /* * generic bound volume/swtich controls @@ -1464,7 +1262,6 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1481,7 +1278,6 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1504,7 +1300,6 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) @@ -1521,7 +1316,6 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); struct hda_ctl_ops snd_hda_bind_vol = { .info = snd_hda_mixer_amp_volume_info, @@ -1529,7 +1323,6 @@ struct hda_ctl_ops snd_hda_bind_vol = { .put = snd_hda_mixer_amp_volume_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_HDA(snd_hda_bind_vol); struct hda_ctl_ops snd_hda_bind_sw = { .info = snd_hda_mixer_amp_switch_info, @@ -1537,7 +1330,6 @@ struct hda_ctl_ops snd_hda_bind_sw = { .put = snd_hda_mixer_amp_switch_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_HDA(snd_hda_bind_sw); /* * SPDIF out controls @@ -1785,11 +1577,9 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) } for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); - if (!kctl) - return -ENOMEM; kctl->id.index = idx; kctl->private_value = nid; - err = snd_hda_ctl_add(codec, kctl); + err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; } @@ -1799,7 +1589,6 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); /* * SPDIF sharing with analog output @@ -1834,10 +1623,9 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, if (!mout->dig_out_nid) return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ - return snd_hda_ctl_add(codec, + return snd_ctl_add(codec->bus->card, snd_ctl_new1(&spdif_share_sw, mout)); } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw); /* * SPDIF input @@ -1937,7 +1725,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); kctl->private_value = nid; - err = snd_hda_ctl_add(codec, kctl); + err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; } @@ -1947,7 +1735,6 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) AC_DIG1_ENABLE; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); #ifdef SND_HDA_NEEDS_RESUME /* @@ -1974,14 +1761,10 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - struct hda_bus *bus = codec->bus; - unsigned int res; int err; - - res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&bus->cmd_mutex); - err = bus->ops.command(bus, res); + mutex_lock(&codec->bus->cmd_mutex); + err = codec->bus->ops.command(codec, nid, direct, verb, parm); if (!err) { struct hda_cache_head *c; u32 key = build_cmd_cache_key(nid, verb); @@ -1989,19 +1772,18 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, if (c) c->val = parm; } - mutex_unlock(&bus->cmd_mutex); + mutex_unlock(&codec->bus->cmd_mutex); snd_hda_power_down(codec); return err; } -EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { - struct hda_cache_head *buffer = codec->cmd_cache.buf.list; + struct hda_cache_head *buffer = codec->cmd_cache.buffer; int i; - for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { + for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { u32 key = buffer->key; if (!key) continue; @@ -2009,7 +1791,6 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec) get_cmd_cache_cmd(key), buffer->val); } } -EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache); /** * snd_hda_sequence_write_cache - sequence writes with caching @@ -2027,7 +1808,6 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); #endif /* SND_HDA_NEEDS_RESUME */ /* @@ -2088,17 +1868,6 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, } } -#ifdef CONFIG_SND_HDA_HWDEP -/* execute additional init verbs */ -static void hda_exec_init_verbs(struct hda_codec *codec) -{ - if (codec->init_verbs.list) - snd_hda_sequence_write(codec, codec->init_verbs.list); -} -#else -static inline void hda_exec_init_verbs(struct hda_codec *codec) {} -#endif - #ifdef SND_HDA_NEEDS_RESUME /* * call suspend and power-down; used both from PM and power-save @@ -2125,7 +1894,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); - hda_exec_init_verbs(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { @@ -2146,37 +1914,28 @@ static void hda_call_codec_resume(struct hda_codec *codec) * * Returns 0 if successful, otherwise a negative error code. */ -int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) +int __devinit snd_hda_build_controls(struct hda_bus *bus) { struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - int err = snd_hda_codec_build_controls(codec); + int err = 0; + /* fake as if already powered-on */ + hda_keep_power_on(codec); + /* then fire up */ + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D0); + /* continue to initialize... */ + if (codec->patch_ops.init) + err = codec->patch_ops.init(codec); + if (!err && codec->patch_ops.build_controls) + err = codec->patch_ops.build_controls(codec); + snd_hda_power_down(codec); if (err < 0) return err; } - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_build_controls); -int snd_hda_codec_build_controls(struct hda_codec *codec) -{ - int err = 0; - /* fake as if already powered-on */ - hda_keep_power_on(codec); - /* then fire up */ - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - hda_exec_init_verbs(codec); - /* continue to initialize... */ - if (codec->patch_ops.init) - err = codec->patch_ops.init(codec); - if (!err && codec->patch_ops.build_controls) - err = codec->patch_ops.build_controls(codec); - snd_hda_power_down(codec); - if (err < 0) - return err; return 0; } @@ -2269,7 +2028,6 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, return val; } -EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats @@ -2284,7 +2042,7 @@ EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); * * Returns 0 if successful, otherwise a negative error code. */ -static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, +int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp) { int i; @@ -2449,7 +2207,6 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, return 1; } -EXPORT_SYMBOL_HDA(snd_hda_is_supported_format); /* * PCM stuff @@ -2479,8 +2236,8 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static int set_pcm_default_values(struct hda_codec *codec, - struct hda_pcm_stream *info) +static int __devinit set_pcm_default_values(struct hda_codec *codec, + struct hda_pcm_stream *info) { /* query support PCM information from the given NID */ if (info->nid && (!info->rates || !info->formats)) { @@ -2506,110 +2263,6 @@ static int set_pcm_default_values(struct hda_codec *codec, return 0; } -/* - * get the empty PCM device number to assign - */ -static int get_empty_pcm_device(struct hda_bus *bus, int type) -{ - static const char *dev_name[HDA_PCM_NTYPES] = { - "Audio", "SPDIF", "HDMI", "Modem" - }; - /* starting device index for each PCM type */ - static int dev_idx[HDA_PCM_NTYPES] = { - [HDA_PCM_TYPE_AUDIO] = 0, - [HDA_PCM_TYPE_SPDIF] = 1, - [HDA_PCM_TYPE_HDMI] = 3, - [HDA_PCM_TYPE_MODEM] = 6 - }; - /* normal audio device indices; not linear to keep compatibility */ - static int audio_idx[4] = { 0, 2, 4, 5 }; - int i, dev; - - switch (type) { - case HDA_PCM_TYPE_AUDIO: - for (i = 0; i < ARRAY_SIZE(audio_idx); i++) { - dev = audio_idx[i]; - if (!test_bit(dev, bus->pcm_dev_bits)) - break; - } - if (i >= ARRAY_SIZE(audio_idx)) { - snd_printk(KERN_WARNING "Too many audio devices\n"); - return -EAGAIN; - } - break; - case HDA_PCM_TYPE_SPDIF: - case HDA_PCM_TYPE_HDMI: - case HDA_PCM_TYPE_MODEM: - dev = dev_idx[type]; - if (test_bit(dev, bus->pcm_dev_bits)) { - snd_printk(KERN_WARNING "%s already defined\n", - dev_name[type]); - return -EAGAIN; - } - break; - default: - snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); - return -EINVAL; - } - set_bit(dev, bus->pcm_dev_bits); - return dev; -} - -/* - * attach a new PCM stream - */ -static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) -{ - struct hda_bus *bus = codec->bus; - struct hda_pcm_stream *info; - int stream, err; - - if (snd_BUG_ON(!pcm->name)) - return -EINVAL; - for (stream = 0; stream < 2; stream++) { - info = &pcm->stream[stream]; - if (info->substreams) { - err = set_pcm_default_values(codec, info); - if (err < 0) - return err; - } - } - return bus->ops.attach_pcm(bus, codec, pcm); -} - -/* assign all PCMs of the given codec */ -int snd_hda_codec_build_pcms(struct hda_codec *codec) -{ - unsigned int pcm; - int err; - - if (!codec->num_pcms) { - if (!codec->patch_ops.build_pcms) - return 0; - err = codec->patch_ops.build_pcms(codec); - if (err < 0) - return err; - } - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - struct hda_pcm *cpcm = &codec->pcm_info[pcm]; - int dev; - - if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) - return 0; /* no substreams assigned */ - - if (!cpcm->pcm) { - dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type); - if (dev < 0) - return 0; - cpcm->device = dev; - err = snd_hda_attach_pcm(codec, cpcm); - if (err < 0) - return err; - } - } - return 0; -} - /** * snd_hda_build_pcms - build PCM information * @bus: the BUS @@ -2641,13 +2294,27 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - int err = snd_hda_codec_build_pcms(codec); + unsigned int pcm, s; + int err; + if (!codec->patch_ops.build_pcms) + continue; + err = codec->patch_ops.build_pcms(codec); if (err < 0) return err; + for (pcm = 0; pcm < codec->num_pcms; pcm++) { + for (s = 0; s < 2; s++) { + struct hda_pcm_stream *info; + info = &codec->pcm_info[pcm].stream[s]; + if (!info->substreams) + continue; + err = set_pcm_default_values(codec, info); + if (err < 0) + return err; + } + } } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_build_pcms); /** * snd_hda_check_board_config - compare the current codec with the config table @@ -2666,11 +2333,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **models, const struct snd_pci_quirk *tbl) { - if (codec->modelname && models) { + if (codec->bus->modelname && models) { int i; for (i = 0; i < num_configs; i++) { if (models[i] && - !strcmp(codec->modelname, models[i])) { + !strcmp(codec->bus->modelname, models[i])) { snd_printd(KERN_INFO "hda_codec: model '%s' is " "selected\n", models[i]); return i; @@ -2703,7 +2370,6 @@ int snd_hda_check_board_config(struct hda_codec *codec, } return -1; } -EXPORT_SYMBOL_HDA(snd_hda_check_board_config); /** * snd_hda_add_new_ctls - create controls from the array @@ -2724,7 +2390,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; - err = snd_hda_ctl_add(codec, kctl); + err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) { if (!codec->addr) return err; @@ -2732,14 +2398,13 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) return -ENOMEM; kctl->id.device = codec->addr; - err = snd_hda_ctl_add(codec, kctl); + err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; } } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, @@ -2749,7 +2414,6 @@ static void hda_power_work(struct work_struct *work) { struct hda_codec *codec = container_of(work, struct hda_codec, power_work.work); - struct hda_bus *bus = codec->bus; if (!codec->power_on || codec->power_count) { codec->power_transition = 0; @@ -2757,8 +2421,8 @@ static void hda_power_work(struct work_struct *work) } hda_call_codec_suspend(codec); - if (bus->ops.pm_notify) - bus->ops.pm_notify(bus); + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); } static void hda_keep_power_on(struct hda_codec *codec) @@ -2769,39 +2433,29 @@ static void hda_keep_power_on(struct hda_codec *codec) void snd_hda_power_up(struct hda_codec *codec) { - struct hda_bus *bus = codec->bus; - codec->power_count++; if (codec->power_on || codec->power_transition) return; codec->power_on = 1; - if (bus->ops.pm_notify) - bus->ops.pm_notify(bus); + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); hda_call_codec_resume(codec); cancel_delayed_work(&codec->power_work); codec->power_transition = 0; } -EXPORT_SYMBOL_HDA(snd_hda_power_up); - -#define power_save(codec) \ - ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) - -#define power_save(codec) \ - ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; if (!codec->power_on || codec->power_count || codec->power_transition) return; - if (power_save(codec)) { + if (power_save) { codec->power_transition = 1; /* avoid reentrance */ schedule_delayed_work(&codec->power_work, - msecs_to_jiffies(power_save(codec) * 1000)); + msecs_to_jiffies(power_save * 1000)); } } -EXPORT_SYMBOL_HDA(snd_hda_power_down); int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, @@ -2838,7 +2492,6 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); #endif /* @@ -2858,7 +2511,6 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, chmode[uinfo->value.enumerated.item].channels); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info); int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2876,7 +2528,6 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get); int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2897,7 +2548,6 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } -EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put); /* * input MUX helper @@ -2918,7 +2568,6 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, strcpy(uinfo->value.enumerated.name, imux->items[index].label); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_input_mux_info); int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, @@ -2940,7 +2589,6 @@ int snd_hda_input_mux_put(struct hda_codec *codec, *cur_val = idx; return 1; } -EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); /* @@ -2993,7 +2641,6 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -3006,7 +2653,6 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); /* * release the digital out @@ -3019,7 +2665,6 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close); /* * set up more restrictions for analog out @@ -3059,7 +2704,6 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, return snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open); /* * set up the i/o for analog out @@ -3118,7 +2762,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); /* * clean up the setting for analog out @@ -3145,7 +2788,6 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); /* * Helper for automatic pin configuration @@ -3431,13 +3073,11 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, return 0; } -EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); /* labels for input pins */ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" }; -EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); #ifdef CONFIG_PM @@ -3465,11 +3105,11 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_suspend); /** * snd_hda_resume - resume the codecs * @bus: the HDA bus + * @state: resume state * * Returns 0 if successful. * @@ -3486,79 +3126,16 @@ int snd_hda_resume(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_resume); -#endif /* CONFIG_PM */ - -/* - * generic arrays - */ - -/* get a new element from the given array - * if it exceeds the pre-allocated array size, re-allocate the array - */ -void *snd_array_new(struct snd_array *array) -{ - if (array->used >= array->alloced) { - int num = array->alloced + array->alloc_align; - void *nlist; - if (snd_BUG_ON(num >= 4096)) - return NULL; - nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); - if (!nlist) - return NULL; - if (array->list) { - memcpy(nlist, array->list, - array->elem_size * array->alloced); - kfree(array->list); - } - array->list = nlist; - array->alloced = num; - } - return snd_array_elem(array, array->used++); -} -EXPORT_SYMBOL_HDA(snd_array_new); - -/* free the given array elements */ -void snd_array_free(struct snd_array *array) -{ - kfree(array->list); - array->used = 0; - array->alloced = 0; - array->list = NULL; -} -EXPORT_SYMBOL_HDA(snd_array_free); - -/* - * used by hda_proc.c and hda_eld.c - */ -void snd_print_pcm_rates(int pcm, char *buf, int buflen) -{ - static unsigned int rates[] = { - 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 - }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) - if (pcm & (1 << i)) - j += snprintf(buf + j, buflen - j, " %d", rates[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} -EXPORT_SYMBOL_HDA(snd_print_pcm_rates); - -void snd_print_pcm_bits(int pcm, char *buf, int buflen) +#ifdef CONFIG_SND_HDA_POWER_SAVE +int snd_hda_codecs_inuse(struct hda_bus *bus) { - static unsigned int bits[] = { 8, 16, 20, 24, 32 }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (AC_SUPPCM_BITS_8 << i)) - j += snprintf(buf + j, buflen - j, " %d", bits[i]); + struct hda_codec *codec; - buf[j] = '\0'; /* necessary when j == 0 */ + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; + } + return 0; } -EXPORT_SYMBOL_HDA(snd_print_pcm_bits); - -MODULE_DESCRIPTION("HDA codec core"); -MODULE_LICENSE("GPL"); +#endif +#endif diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5587d416229f..60468f562400 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -520,36 +520,6 @@ enum { #define HDA_MAX_CODEC_ADDRESS 0x0f /* - * generic arrays - */ -struct snd_array { - unsigned int used; - unsigned int alloced; - unsigned int elem_size; - unsigned int alloc_align; - void *list; -}; - -void *snd_array_new(struct snd_array *array); -void snd_array_free(struct snd_array *array); -static inline void snd_array_init(struct snd_array *array, unsigned int size, - unsigned int align) -{ - array->elem_size = size; - array->alloc_align = align; -} - -static inline void *snd_array_elem(struct snd_array *array, unsigned int idx) -{ - return array->list + idx * array->elem_size; -} - -static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) -{ - return (unsigned long)(ptr - array->list) / array->elem_size; -} - -/* * Structures */ @@ -566,17 +536,15 @@ typedef u16 hda_nid_t; /* bus operators */ struct hda_bus_ops { /* send a single command */ - int (*command)(struct hda_bus *bus, unsigned int cmd); + int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, + unsigned int verb, unsigned int parm); /* get a response from the last command */ - unsigned int (*get_response)(struct hda_bus *bus); + unsigned int (*get_response)(struct hda_codec *codec); /* free the private data */ void (*private_free)(struct hda_bus *); - /* attach a PCM stream */ - int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *pcm); #ifdef CONFIG_SND_HDA_POWER_SAVE /* notify power-up/down from codec to controller */ - void (*pm_notify)(struct hda_bus *bus); + void (*pm_notify)(struct hda_codec *codec); #endif }; @@ -585,7 +553,6 @@ struct hda_bus_template { void *private_data; struct pci_dev *pci; const char *modelname; - int *power_save; struct hda_bus_ops ops; }; @@ -602,7 +569,6 @@ struct hda_bus { void *private_data; struct pci_dev *pci; const char *modelname; - int *power_save; struct hda_bus_ops ops; /* codec linked list */ @@ -615,12 +581,10 @@ struct hda_bus { /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; - /* assigned PCMs */ - DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); + struct snd_info_entry *proc; /* misc op flags */ unsigned int needs_damn_long_delay :1; - unsigned int shutdown :1; /* being unloaded */ }; /* @@ -640,16 +604,6 @@ struct hda_codec_preset { int (*patch)(struct hda_codec *codec); }; -struct hda_codec_preset_list { - const struct hda_codec_preset *preset; - struct module *owner; - struct list_head list; -}; - -/* initial hook */ -int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset); -int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset); - /* ops set by the preset patch */ struct hda_codec_ops { int (*build_controls)(struct hda_codec *codec); @@ -681,7 +635,10 @@ struct hda_amp_info { struct hda_cache_rec { u16 hash[64]; /* hash table for index */ - struct snd_array buf; /* record entries */ + unsigned int num_entries; /* number of assigned entries */ + unsigned int size; /* allocated size */ + unsigned int record_size; /* record size (including header) */ + void *buffer; /* hash table entries */ }; /* PCM callbacks */ @@ -723,8 +680,7 @@ struct hda_pcm { char *name; struct hda_pcm_stream stream[2]; unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */ - int device; /* device number to assign */ - struct snd_pcm *pcm; /* assigned PCM instance */ + int device; /* assigned device number */ }; /* codec information */ @@ -743,9 +699,6 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; - struct module *owner; - const char *name; /* codec name */ - const char *modelname; /* model name for preset */ /* set by patch */ struct hda_codec_ops patch_ops; @@ -765,8 +718,6 @@ struct hda_codec { hda_nid_t start_nid; u32 *wcaps; - struct snd_array mixers; /* list of assigned mixer elements */ - struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ @@ -776,11 +727,7 @@ struct hda_codec { unsigned int spdif_in_enable; /* SPDIF input enable? */ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ -#ifdef CONFIG_SND_HDA_HWDEP struct snd_hwdep *hwdep; /* assigned hwdep device */ - struct snd_array init_verbs; /* additional init verbs */ - struct snd_array hints; /* additional hints */ -#endif /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each @@ -793,10 +740,6 @@ struct hda_codec { int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ #endif - - /* codec-specific additional proc output */ - void (*proc_widget_hook)(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid); }; /* direction */ @@ -856,13 +799,11 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); * Mixer */ int snd_hda_build_controls(struct hda_bus *bus); -int snd_hda_codec_build_controls(struct hda_codec *codec); /* * PCM */ int snd_hda_build_pcms(struct hda_bus *bus); -int snd_hda_codec_build_pcms(struct hda_codec *codec); void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format); @@ -871,6 +812,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps); +int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, + u32 *ratesp, u64 *formatsp, unsigned int *bpsp); int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, unsigned int format); @@ -888,38 +831,18 @@ int snd_hda_resume(struct hda_bus *bus); #endif /* - * get widget information - */ -const char *snd_hda_get_jack_connectivity(u32 cfg); -const char *snd_hda_get_jack_type(u32 cfg); -const char *snd_hda_get_jack_location(u32 cfg); - -/* * power saving */ #ifdef CONFIG_SND_HDA_POWER_SAVE void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); #define snd_hda_codec_needs_resume(codec) codec->power_count +int snd_hda_codecs_inuse(struct hda_bus *bus); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} #define snd_hda_codec_needs_resume(codec) 1 -#endif - -/* - * Codec modularization - */ - -/* Export symbols only for communication with codec drivers; - * When built in kernel, all HD-audio drivers are supposed to be statically - * linked to the kernel. Thus, the symbols don't have to (or shouldn't) be - * exported unless it's built as a module. - */ -#ifdef MODULE -#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym) -#else -#define EXPORT_SYMBOL_HDA(sym) +#define snd_hda_codecs_inuse(bus) 1 #endif #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c deleted file mode 100644 index fcad5ec31773..000000000000 --- a/sound/pci/hda/hda_eld.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Generic routines and proc interface for ELD(EDID Like Data) information - * - * Copyright(c) 2008 Intel Corporation. - * - * Authors: - * Wu Fengguang <wfg@linux.intel.com> - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/init.h> -#include <sound/core.h> -#include <asm/unaligned.h> -#include "hda_codec.h" -#include "hda_local.h" - -enum eld_versions { - ELD_VER_CEA_861D = 2, - ELD_VER_PARTIAL = 31, -}; - -enum cea_edid_versions { - CEA_EDID_VER_NONE = 0, - CEA_EDID_VER_CEA861 = 1, - CEA_EDID_VER_CEA861A = 2, - CEA_EDID_VER_CEA861BCD = 3, - CEA_EDID_VER_RESERVED = 4, -}; - -static char *cea_speaker_allocation_names[] = { - /* 0 */ "FL/FR", - /* 1 */ "LFE", - /* 2 */ "FC", - /* 3 */ "RL/RR", - /* 4 */ "RC", - /* 5 */ "FLC/FRC", - /* 6 */ "RLC/RRC", - /* 7 */ "FLW/FRW", - /* 8 */ "FLH/FRH", - /* 9 */ "TC", - /* 10 */ "FCH", -}; - -static char *eld_connection_type_names[4] = { - "HDMI", - "DisplayPort", - "2-reserved", - "3-reserved" -}; - -enum cea_audio_coding_types { - AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, - AUDIO_CODING_TYPE_LPCM = 1, - AUDIO_CODING_TYPE_AC3 = 2, - AUDIO_CODING_TYPE_MPEG1 = 3, - AUDIO_CODING_TYPE_MP3 = 4, - AUDIO_CODING_TYPE_MPEG2 = 5, - AUDIO_CODING_TYPE_AACLC = 6, - AUDIO_CODING_TYPE_DTS = 7, - AUDIO_CODING_TYPE_ATRAC = 8, - AUDIO_CODING_TYPE_SACD = 9, - AUDIO_CODING_TYPE_EAC3 = 10, - AUDIO_CODING_TYPE_DTS_HD = 11, - AUDIO_CODING_TYPE_MLP = 12, - AUDIO_CODING_TYPE_DST = 13, - AUDIO_CODING_TYPE_WMAPRO = 14, - AUDIO_CODING_TYPE_REF_CXT = 15, - /* also include valid xtypes below */ - AUDIO_CODING_TYPE_HE_AAC = 15, - AUDIO_CODING_TYPE_HE_AAC2 = 16, - AUDIO_CODING_TYPE_MPEG_SURROUND = 17, -}; - -enum cea_audio_coding_xtypes { - AUDIO_CODING_XTYPE_HE_REF_CT = 0, - AUDIO_CODING_XTYPE_HE_AAC = 1, - AUDIO_CODING_XTYPE_HE_AAC2 = 2, - AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, - AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, -}; - -static char *cea_audio_coding_type_names[] = { - /* 0 */ "undefined", - /* 1 */ "LPCM", - /* 2 */ "AC-3", - /* 3 */ "MPEG1", - /* 4 */ "MP3", - /* 5 */ "MPEG2", - /* 6 */ "AAC-LC", - /* 7 */ "DTS", - /* 8 */ "ATRAC", - /* 9 */ "DSD (One Bit Audio)", - /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", - /* 11 */ "DTS-HD", - /* 12 */ "MLP (Dolby TrueHD)", - /* 13 */ "DST", - /* 14 */ "WMAPro", - /* 15 */ "HE-AAC", - /* 16 */ "HE-AACv2", - /* 17 */ "MPEG Surround", -}; - -/* - * The following two lists are shared between - * - HDMI audio InfoFrame (source to sink) - * - CEA E-EDID Extension (sink to source) - */ - -/* - * SS1:SS0 index => sample size - */ -static int cea_sample_sizes[4] = { - 0, /* 0: Refer to Stream Header */ - AC_SUPPCM_BITS_16, /* 1: 16 bits */ - AC_SUPPCM_BITS_20, /* 2: 20 bits */ - AC_SUPPCM_BITS_24, /* 3: 24 bits */ -}; - -/* - * SF2:SF1:SF0 index => sampling frequency - */ -static int cea_sampling_frequencies[8] = { - 0, /* 0: Refer to Stream Header */ - SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ - SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ - SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ - SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ - SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ - SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ - SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ -}; - -static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, - int byte_index) -{ - unsigned int val; - - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_HDMI_ELDD, byte_index); - -#ifdef BE_PARANOID - printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); -#endif - - if ((val & AC_ELDD_ELD_VALID) == 0) { - snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", - byte_index); - val = 0; - } - - return val & AC_ELDD_ELD_DATA; -} - -#define GRAB_BITS(buf, byte, lowbit, bits) \ -({ \ - BUILD_BUG_ON(lowbit > 7); \ - BUILD_BUG_ON(bits > 8); \ - BUILD_BUG_ON(bits <= 0); \ - \ - (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ -}) - -static void hdmi_update_short_audio_desc(struct cea_sad *a, - const unsigned char *buf) -{ - int i; - int val; - - val = GRAB_BITS(buf, 1, 0, 7); - a->rates = 0; - for (i = 0; i < 7; i++) - if (val & (1 << i)) - a->rates |= cea_sampling_frequencies[i + 1]; - - a->channels = GRAB_BITS(buf, 0, 0, 3); - a->channels++; - - a->format = GRAB_BITS(buf, 0, 3, 4); - switch (a->format) { - case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - snd_printd(KERN_INFO - "HDMI: audio coding type 0 not expected\n"); - break; - - case AUDIO_CODING_TYPE_LPCM: - val = GRAB_BITS(buf, 2, 0, 3); - a->sample_bits = 0; - for (i = 0; i < 3; i++) - if (val & (1 << i)) - a->sample_bits |= cea_sample_sizes[i + 1]; - break; - - case AUDIO_CODING_TYPE_AC3: - case AUDIO_CODING_TYPE_MPEG1: - case AUDIO_CODING_TYPE_MP3: - case AUDIO_CODING_TYPE_MPEG2: - case AUDIO_CODING_TYPE_AACLC: - case AUDIO_CODING_TYPE_DTS: - case AUDIO_CODING_TYPE_ATRAC: - a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); - a->max_bitrate *= 8000; - break; - - case AUDIO_CODING_TYPE_SACD: - break; - - case AUDIO_CODING_TYPE_EAC3: - break; - - case AUDIO_CODING_TYPE_DTS_HD: - break; - - case AUDIO_CODING_TYPE_MLP: - break; - - case AUDIO_CODING_TYPE_DST: - break; - - case AUDIO_CODING_TYPE_WMAPRO: - a->profile = GRAB_BITS(buf, 2, 0, 3); - break; - - case AUDIO_CODING_TYPE_REF_CXT: - a->format = GRAB_BITS(buf, 2, 3, 5); - if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || - a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - snd_printd(KERN_INFO - "HDMI: audio coding xtype %d not expected\n", - a->format); - a->format = 0; - } else - a->format += AUDIO_CODING_TYPE_HE_AAC - - AUDIO_CODING_XTYPE_HE_AAC; - break; - } -} - -/* - * Be careful, ELD buf could be totally rubbish! - */ -static int hdmi_update_eld(struct hdmi_eld *e, - const unsigned char *buf, int size) -{ - int mnl; - int i; - - e->eld_ver = GRAB_BITS(buf, 0, 3, 5); - if (e->eld_ver != ELD_VER_CEA_861D && - e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", - e->eld_ver); - goto out_fail; - } - - e->eld_size = size; - e->baseline_len = GRAB_BITS(buf, 2, 0, 8); - mnl = GRAB_BITS(buf, 4, 0, 5); - e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); - - e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); - e->support_ai = GRAB_BITS(buf, 5, 1, 1); - e->conn_type = GRAB_BITS(buf, 5, 2, 2); - e->sad_count = GRAB_BITS(buf, 5, 4, 4); - - e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; - e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); - - e->port_id = get_unaligned_le64(buf + 8); - - /* not specified, but the spec's tendency is little endian */ - e->manufacture_id = get_unaligned_le16(buf + 16); - e->product_id = get_unaligned_le16(buf + 18); - - if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); - goto out_fail; - } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); - goto out_fail; - } else - strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); - - for (i = 0; i < e->sad_count; i++) { - if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); - goto out_fail; - } - hdmi_update_short_audio_desc(e->sad + i, - buf + ELD_FIXED_BYTES + mnl + 3 * i); - } - - return 0; - -out_fail: - e->eld_ver = 0; - return -EINVAL; -} - -static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); -} - -static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) -{ - int eldv; - int present; - - present = hdmi_present_sense(codec, nid); - eldv = (present & AC_PINSENSE_ELDV); - present = (present & AC_PINSENSE_PRESENCE); - -#ifdef CONFIG_SND_DEBUG_VERBOSE - printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n", - !!present, !!eldv); -#endif - - return eldv && present; -} - -int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - -int snd_hdmi_get_eld(struct hdmi_eld *eld, - struct hda_codec *codec, hda_nid_t nid) -{ - int i; - int ret; - int size; - unsigned char *buf; - - if (!hdmi_eld_valid(codec, nid)) - return -ENOENT; - - size = snd_hdmi_get_eld_size(codec, nid); - if (size == 0) { - /* wfg: workaround for ASUS P5E-VM HDMI board */ - snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); - size = 128; - } - if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { - snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); - return -ERANGE; - } - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - for (i = 0; i < size; i++) - buf[i] = hdmi_get_eld_byte(codec, nid, i); - - ret = hdmi_update_eld(eld, buf, size); - - kfree(buf); - return ret; -} - -static void hdmi_show_short_audio_desc(struct cea_sad *a) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; - - if (!a->format) - return; - - snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - - if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); - else if (a->max_bitrate) - snprintf(buf2, sizeof(buf2), - ", max bitrate = %d", a->max_bitrate); - else - buf2[0] = '\0'; - - printk(KERN_INFO "HDMI: supports coding type %s:" - " channels = %d, rates =%s%s\n", - cea_audio_coding_type_names[a->format], - a->channels, - buf, - buf2); -} - -void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) -{ - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { - if (spk_alloc & (1 << i)) - j += snprintf(buf + j, buflen - j, " %s", - cea_speaker_allocation_names[i]); - } - buf[j] = '\0'; /* necessary when j == 0 */ -} - -void snd_hdmi_show_eld(struct hdmi_eld *e) -{ - int i; - - printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n", - e->monitor_name, - eld_connection_type_names[e->conn_type]); - - if (e->spk_alloc) { - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - printk(KERN_INFO "HDMI: available speakers:%s\n", buf); - } - - for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(e->sad + i); -} - -#ifdef CONFIG_PROC_FS - -static void hdmi_print_sad_info(int i, struct cea_sad *a, - struct snd_info_buffer *buffer) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - - snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", - i, a->format, cea_audio_coding_type_names[a->format]); - snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); - - snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); - - if (a->format == AUDIO_CODING_TYPE_LPCM) { - snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", - i, a->sample_bits, buf); - } - - if (a->max_bitrate) - snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", - i, a->max_bitrate); - - if (a->profile) - snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); -} - -static void hdmi_print_eld_info(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct hdmi_eld *e = entry->private_data; - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - int i; - static char *eld_versoin_names[32] = { - "reserved", - "reserved", - "CEA-861D or below", - [3 ... 30] = "reserved", - [31] = "partial" - }; - static char *cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - [4 ... 7] = "reserved" - }; - - snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); - snd_iprintf(buffer, "connection_type\t\t%s\n", - eld_connection_type_names[e->conn_type]); - snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, - eld_versoin_names[e->eld_ver]); - snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, - cea_edid_version_names[e->cea_edid_ver]); - snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); - snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); - snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); - snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); - snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); - snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); - - snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); - - snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); - - for (i = 0; i < e->sad_count; i++) - hdmi_print_sad_info(i, e->sad + i, buffer); -} - -static void hdmi_write_eld_info(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct hdmi_eld *e = entry->private_data; - char line[64]; - char name[64]; - char *sname; - long long val; - int n; - - while (!snd_info_get_line(buffer, line, sizeof(line))) { - if (sscanf(line, "%s %llx", name, &val) != 2) - continue; - /* - * We don't allow modification to these fields: - * monitor_name manufacture_id product_id - * eld_version edid_version - */ - if (!strcmp(name, "connection_type")) - e->conn_type = val; - else if (!strcmp(name, "port_id")) - e->port_id = val; - else if (!strcmp(name, "support_hdcp")) - e->support_hdcp = val; - else if (!strcmp(name, "support_ai")) - e->support_ai = val; - else if (!strcmp(name, "audio_sync_delay")) - e->aud_synch_delay = val; - else if (!strcmp(name, "speakers")) - e->spk_alloc = val; - else if (!strcmp(name, "sad_count")) - e->sad_count = val; - else if (!strncmp(name, "sad", 3)) { - sname = name + 4; - n = name[3] - '0'; - if (name[4] >= '0' && name[4] <= '9') { - sname++; - n = 10 * n + name[4] - '0'; - } - if (n < 0 || n > 31) /* double the CEA limit */ - continue; - if (!strcmp(sname, "_coding_type")) - e->sad[n].format = val; - else if (!strcmp(sname, "_channels")) - e->sad[n].channels = val; - else if (!strcmp(sname, "_rates")) - e->sad[n].rates = val; - else if (!strcmp(sname, "_bits")) - e->sad[n].sample_bits = val; - else if (!strcmp(sname, "_max_bitrate")) - e->sad[n].max_bitrate = val; - else if (!strcmp(sname, "_profile")) - e->sad[n].profile = val; - if (n >= e->sad_count) - e->sad_count = n + 1; - } - } -} - - -int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) -{ - char name[32]; - struct snd_info_entry *entry; - int err; - - snprintf(name, sizeof(name), "eld#%d", codec->addr); - err = snd_card_proc_new(codec->bus->card, name, &entry); - if (err < 0) - return err; - - snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); - entry->c.text.write = hdmi_write_eld_info; - entry->mode |= S_IWUSR; - eld->proc_entry = entry; - - return 0; -} - -void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) -{ - if (!codec->bus->shutdown && eld->proc_entry) { - snd_device_free(codec->bus->card, eld->proc_entry); - eld->proc_entry = NULL; - } -} - -#endif /* CONFIG_PROC_FS */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 65745e96dc70..0ca30894f7c6 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -723,8 +723,7 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if (is_loopback) add_input_loopback(codec, node->nid, HDA_INPUT, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); - if (err < 0) + if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; created = 1; } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && @@ -733,8 +732,7 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if (is_loopback) add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); - if (err < 0) + if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; created = 1; } @@ -747,16 +745,14 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); - if (err < 0) + if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; created = 1; } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); - if (err < 0) + if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; created = 1; } @@ -853,8 +849,8 @@ static int build_input_controls(struct hda_codec *codec) } /* create input MUX if multiple sources are available */ - err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec)); - if (err < 0) + if ((err = snd_ctl_add(codec->bus->card, + snd_ctl_new1(&cap_sel, codec))) < 0) return err; /* no volume control? */ @@ -871,8 +867,8 @@ static int build_input_controls(struct hda_codec *codec) HDA_CODEC_VOLUME(name, adc_node->nid, spec->input_mux.items[i].index, HDA_INPUT); - err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); - if (err < 0) + if ((err = snd_ctl_add(codec->bus->card, + snd_ctl_new1(&knew, codec))) < 0) return err; } @@ -1101,4 +1097,3 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec) snd_hda_generic_free(codec); return err; } -EXPORT_SYMBOL(snd_hda_parse_generic_codec); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 300ab407cf42..6e18a422d993 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,12 +23,10 @@ #include <linux/pci.h> #include <linux/compat.h> #include <linux/mutex.h> -#include <linux/ctype.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" #include <sound/hda_hwdep.h> -#include <sound/minors.h> /* * write/read an out-of-bound verb @@ -97,26 +95,7 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) return 0; } -static void clear_hwdep_elements(struct hda_codec *codec) -{ - char **head; - int i; - - /* clear init verbs */ - snd_array_free(&codec->init_verbs); - /* clear hints */ - head = codec->hints.list; - for (i = 0; i < codec->hints.used; i++, head++) - kfree(*head); - snd_array_free(&codec->hints); -} - -static void hwdep_free(struct snd_hwdep *hwdep) -{ - clear_hwdep_elements(hwdep->private_data); -} - -int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) +int __devinit snd_hda_create_hwdep(struct hda_codec *codec) { char hwname[16]; struct snd_hwdep *hwdep; @@ -130,7 +109,6 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) sprintf(hwdep->name, "HDA Codec %d", codec->addr); hwdep->iface = SNDRV_HWDEP_IFACE_HDA; hwdep->private_data = codec; - hwdep->private_free = hwdep_free; hwdep->exclusive = 1; hwdep->ops.open = hda_hwdep_open; @@ -139,215 +117,5 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; #endif - snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); - snd_array_init(&codec->hints, sizeof(char *), 32); - return 0; } - -#ifdef CONFIG_SND_HDA_RECONFIG - -/* - * sysfs interface - */ - -static int clear_codec(struct hda_codec *codec) -{ - snd_hda_codec_reset(codec); - clear_hwdep_elements(codec); - return 0; -} - -static int reconfig_codec(struct hda_codec *codec) -{ - int err; - - snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); - snd_hda_codec_reset(codec); - err = snd_hda_codec_configure(codec); - if (err < 0) - return err; - /* rebuild PCMs */ - err = snd_hda_codec_build_pcms(codec); - if (err < 0) - return err; - /* rebuild mixers */ - err = snd_hda_codec_build_controls(codec); - if (err < 0) - return err; - return 0; -} - -/* - * allocate a string at most len chars, and remove the trailing EOL - */ -static char *kstrndup_noeol(const char *src, size_t len) -{ - char *s = kstrndup(src, len, GFP_KERNEL); - char *p; - if (!s) - return NULL; - p = strchr(s, '\n'); - if (p) - *p = 0; - return s; -} - -#define CODEC_INFO_SHOW(type) \ -static ssize_t type##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - return sprintf(buf, "0x%x\n", codec->type); \ -} - -#define CODEC_INFO_STR_SHOW(type) \ -static ssize_t type##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - return sprintf(buf, "%s\n", \ - codec->type ? codec->type : ""); \ -} - -CODEC_INFO_SHOW(vendor_id); -CODEC_INFO_SHOW(subsystem_id); -CODEC_INFO_SHOW(revision_id); -CODEC_INFO_SHOW(afg); -CODEC_INFO_SHOW(mfg); -CODEC_INFO_STR_SHOW(name); -CODEC_INFO_STR_SHOW(modelname); - -#define CODEC_INFO_STORE(type) \ -static ssize_t type##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - char *after; \ - codec->type = simple_strtoul(buf, &after, 0); \ - return count; \ -} - -#define CODEC_INFO_STR_STORE(type) \ -static ssize_t type##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - char *s = kstrndup_noeol(buf, 64); \ - if (!s) \ - return -ENOMEM; \ - kfree(codec->type); \ - codec->type = s; \ - return count; \ -} - -CODEC_INFO_STORE(vendor_id); -CODEC_INFO_STORE(subsystem_id); -CODEC_INFO_STORE(revision_id); -CODEC_INFO_STR_STORE(name); -CODEC_INFO_STR_STORE(modelname); - -#define CODEC_ACTION_STORE(type) \ -static ssize_t type##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - int err = 0; \ - if (*buf) \ - err = type##_codec(codec); \ - return err < 0 ? err : count; \ -} - -CODEC_ACTION_STORE(reconfig); -CODEC_ACTION_STORE(clear); - -static ssize_t init_verbs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - char *p; - struct hda_verb verb, *v; - - verb.nid = simple_strtoul(buf, &p, 0); - verb.verb = simple_strtoul(p, &p, 0); - verb.param = simple_strtoul(p, &p, 0); - if (!verb.nid || !verb.verb || !verb.param) - return -EINVAL; - v = snd_array_new(&codec->init_verbs); - if (!v) - return -ENOMEM; - *v = verb; - return count; -} - -static ssize_t hints_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - char *p; - char **hint; - - if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n') - return count; - p = kstrndup_noeol(buf, 1024); - if (!p) - return -ENOMEM; - hint = snd_array_new(&codec->hints); - if (!hint) { - kfree(p); - return -ENOMEM; - } - *hint = p; - return count; -} - -#define CODEC_ATTR_RW(type) \ - __ATTR(type, 0644, type##_show, type##_store) -#define CODEC_ATTR_RO(type) \ - __ATTR_RO(type) -#define CODEC_ATTR_WO(type) \ - __ATTR(type, 0200, NULL, type##_store) - -static struct device_attribute codec_attrs[] = { - CODEC_ATTR_RW(vendor_id), - CODEC_ATTR_RW(subsystem_id), - CODEC_ATTR_RW(revision_id), - CODEC_ATTR_RO(afg), - CODEC_ATTR_RO(mfg), - CODEC_ATTR_RW(name), - CODEC_ATTR_RW(modelname), - CODEC_ATTR_WO(init_verbs), - CODEC_ATTR_WO(hints), - CODEC_ATTR_WO(reconfig), - CODEC_ATTR_WO(clear), -}; - -/* - * create sysfs files on hwdep directory - */ -int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) -{ - struct snd_hwdep *hwdep = codec->hwdep; - int i; - - for (i = 0; i < ARRAY_SIZE(codec_attrs); i++) - snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, - hwdep->device, &codec_attrs[i]); - return 0; -} - -#endif /* CONFIG_SND_HDA_RECONFIG */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 29836cc63d8f..35722ec920cb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -83,10 +83,7 @@ module_param(enable_msi, int, 0444); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); #ifdef CONFIG_SND_HDA_POWER_SAVE -static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; -module_param(power_save, int, 0644); -MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " - "(in second, 0 = disable)."); +/* power_save option is defined in hda_codec.c */ /* reset the HD-audio controller in power save mode. * this may give more power-saving, but will take longer time to @@ -295,8 +292,6 @@ enum { /* Define VIA HD Audio Device ID*/ #define VIA_HDAC_DEVICE_ID 0x3288 -/* HD Audio class code */ -#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 /* */ @@ -397,7 +392,6 @@ struct azx { unsigned int msi :1; unsigned int irq_pending_warned :1; unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */ - unsigned int probing :1; /* codec probing phase */ /* for debugging */ unsigned int last_cmd; /* last issued command (to sync) */ @@ -420,7 +414,6 @@ enum { AZX_DRIVER_ULI, AZX_DRIVER_NVIDIA, AZX_DRIVER_TERA, - AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -434,7 +427,6 @@ static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ULI] = "HDA ULI M5461", [AZX_DRIVER_NVIDIA] = "HDA NVidia", [AZX_DRIVER_TERA] = "HDA Teradici", - [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; /* @@ -535,9 +527,9 @@ static void azx_free_cmd_io(struct azx *chip) } /* send a command */ -static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) +static int azx_corb_send_cmd(struct hda_codec *codec, u32 val) { - struct azx *chip = bus->private_data; + struct azx *chip = codec->bus->private_data; unsigned int wp; /* add command to corb */ @@ -585,9 +577,9 @@ static void azx_update_rirb(struct azx *chip) } /* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_bus *bus) +static unsigned int azx_rirb_get_response(struct hda_codec *codec) { - struct azx *chip = bus->private_data; + struct azx *chip = codec->bus->private_data; unsigned long timeout; again: @@ -604,7 +596,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) } if (time_after(jiffies, timeout)) break; - if (bus->needs_damn_long_delay) + if (codec->bus->needs_damn_long_delay) msleep(2); /* temporary workaround */ else { udelay(10); @@ -632,14 +624,6 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) goto again; } - if (chip->probing) { - /* If this critical timeout happens during the codec probing - * phase, this is likely an access to a non-existing codec - * slot. Better to return an error and reset the system. - */ - return -1; - } - snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " "switching to single_cmd mode: last cmd=0x%08x\n", chip->last_cmd); @@ -662,9 +646,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) */ /* send a command */ -static int azx_single_send_cmd(struct hda_bus *bus, u32 val) +static int azx_single_send_cmd(struct hda_codec *codec, u32 val) { - struct azx *chip = bus->private_data; + struct azx *chip = codec->bus->private_data; int timeout = 50; while (timeout--) { @@ -687,9 +671,9 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) } /* receive a response */ -static unsigned int azx_single_get_response(struct hda_bus *bus) +static unsigned int azx_single_get_response(struct hda_codec *codec) { - struct azx *chip = bus->private_data; + struct azx *chip = codec->bus->private_data; int timeout = 50; while (timeout--) { @@ -712,29 +696,38 @@ static unsigned int azx_single_get_response(struct hda_bus *bus) */ /* send a command */ -static int azx_send_cmd(struct hda_bus *bus, unsigned int val) +static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, + unsigned int para) { - struct azx *chip = bus->private_data; - + struct azx *chip = codec->bus->private_data; + u32 val; + + val = (u32)(codec->addr & 0x0f) << 28; + val |= (u32)direct << 27; + val |= (u32)nid << 20; + val |= verb << 8; + val |= para; chip->last_cmd = val; + if (chip->single_cmd) - return azx_single_send_cmd(bus, val); + return azx_single_send_cmd(codec, val); else - return azx_corb_send_cmd(bus, val); + return azx_corb_send_cmd(codec, val); } /* get a response */ -static unsigned int azx_get_response(struct hda_bus *bus) +static unsigned int azx_get_response(struct hda_codec *codec) { - struct azx *chip = bus->private_data; + struct azx *chip = codec->bus->private_data; if (chip->single_cmd) - return azx_single_get_response(bus); + return azx_single_get_response(codec); else - return azx_rirb_get_response(bus); + return azx_rirb_get_response(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static void azx_power_notify(struct hda_bus *bus); +static void azx_power_notify(struct hda_codec *codec); #endif /* reset codec link */ @@ -1191,28 +1184,6 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) return 0; } -/* - * Probe the given codec address - */ -static int probe_codec(struct azx *chip, int addr) -{ - unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | - (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res; - - chip->probing = 1; - azx_send_cmd(chip->bus, cmd); - res = azx_get_response(chip->bus); - chip->probing = 0; - if (res == -1) - return -EIO; - snd_printdd("hda_intel: codec #%d probed OK\n", addr); - return 0; -} - -static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *cpcm); -static void azx_stop_chip(struct azx *chip); /* * Codec initialization @@ -1223,12 +1194,21 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { [AZX_DRIVER_TERA] = 1, }; +/* number of slots to probe as default + * this can be different from azx_max_codecs[] -- e.g. some boards + * report wrongly the non-existing 4th slot availability + */ +static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = { + [AZX_DRIVER_ICH] = 3, + [AZX_DRIVER_ATI] = 3, +}; + static int __devinit azx_codec_create(struct azx *chip, const char *model, unsigned int codec_probe_mask) { struct hda_bus_template bus_temp; - int c, codecs, err; - int max_slots; + int c, codecs, audio_codecs, err; + int def_slots, max_slots; memset(&bus_temp, 0, sizeof(bus_temp)); bus_temp.private_data = chip; @@ -1236,9 +1216,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; - bus_temp.ops.attach_pcm = azx_attach_pcm_stream; #ifdef CONFIG_SND_HDA_POWER_SAVE - bus_temp.power_save = &power_save; bus_temp.ops.pm_notify = azx_power_notify; #endif @@ -1249,43 +1227,33 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, if (chip->driver_type == AZX_DRIVER_NVIDIA) chip->bus->needs_damn_long_delay = 1; - codecs = 0; + codecs = audio_codecs = 0; max_slots = azx_max_codecs[chip->driver_type]; if (!max_slots) max_slots = AZX_MAX_CODECS; - - /* First try to probe all given codec slots */ - for (c = 0; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { - if (probe_codec(chip, c) < 0) { - /* Some BIOSen give you wrong codec addresses - * that don't exist - */ - snd_printk(KERN_WARNING - "hda_intel: Codec #%d probe error; " - "disabling it...\n", c); - chip->codec_mask &= ~(1 << c); - /* More badly, accessing to a non-existing - * codec often screws up the controller chip, - * and distrubs the further communications. - * Thus if an error occurs during probing, - * better to reset the controller chip to - * get back to the sanity state. - */ - azx_stop_chip(chip); - azx_init_chip(chip); - } - } - } - - /* Then create codec instances */ - for (c = 0; c < max_slots; c++) { + def_slots = azx_default_codecs[chip->driver_type]; + if (!def_slots) + def_slots = max_slots; + for (c = 0; c < def_slots; c++) { if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { struct hda_codec *codec; err = snd_hda_codec_new(chip->bus, c, &codec); if (err < 0) continue; codecs++; + if (codec->afg) + audio_codecs++; + } + } + if (!audio_codecs) { + /* probe additional slots if no codec is found */ + for (; c < max_slots; c++) { + if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { + err = snd_hda_codec_new(chip->bus, c, NULL); + if (err < 0) + continue; + codecs++; + } } } if (!codecs) { @@ -1754,59 +1722,111 @@ static struct snd_pcm_ops azx_pcm_ops = { static void azx_pcm_free(struct snd_pcm *pcm) { - struct azx_pcm *apcm = pcm->private_data; - if (apcm) { - apcm->chip->pcm[pcm->device] = NULL; - kfree(apcm); - } + kfree(pcm->private_data); } -static int -azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *cpcm) +static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, + struct hda_pcm *cpcm) { - struct azx *chip = bus->private_data; + int err; struct snd_pcm *pcm; struct azx_pcm *apcm; - int pcm_dev = cpcm->device; - int s, err; - if (pcm_dev >= AZX_MAX_PCMS) { - snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", - pcm_dev); + /* if no substreams are defined for both playback and capture, + * it's just a placeholder. ignore it. + */ + if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) + return 0; + + if (snd_BUG_ON(!cpcm->name)) return -EINVAL; - } - if (chip->pcm[pcm_dev]) { - snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev); - return -EBUSY; - } - err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, - cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, - cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, + + err = snd_pcm_new(chip->card, cpcm->name, cpcm->device, + cpcm->stream[0].substreams, + cpcm->stream[1].substreams, &pcm); if (err < 0) return err; strcpy(pcm->name, cpcm->name); - apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); + apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); if (apcm == NULL) return -ENOMEM; apcm->chip = chip; apcm->codec = codec; + apcm->hinfo[0] = &cpcm->stream[0]; + apcm->hinfo[1] = &cpcm->stream[1]; pcm->private_data = apcm; pcm->private_free = azx_pcm_free; - if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) - pcm->dev_class = SNDRV_PCM_CLASS_MODEM; - chip->pcm[pcm_dev] = pcm; - cpcm->pcm = pcm; - for (s = 0; s < 2; s++) { - apcm->hinfo[s] = &cpcm->stream[s]; - if (cpcm->stream[s].substreams) - snd_pcm_set_ops(pcm, s, &azx_pcm_ops); - } - /* buffer pre-allocation */ + if (cpcm->stream[0].substreams) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); + if (cpcm->stream[1].substreams) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 1024 * 64, 32 * 1024 * 1024); + chip->pcm[cpcm->device] = pcm; + return 0; +} + +static int __devinit azx_pcm_create(struct azx *chip) +{ + static const char *dev_name[HDA_PCM_NTYPES] = { + "Audio", "SPDIF", "HDMI", "Modem" + }; + /* starting device index for each PCM type */ + static int dev_idx[HDA_PCM_NTYPES] = { + [HDA_PCM_TYPE_AUDIO] = 0, + [HDA_PCM_TYPE_SPDIF] = 1, + [HDA_PCM_TYPE_HDMI] = 3, + [HDA_PCM_TYPE_MODEM] = 6 + }; + /* normal audio device indices; not linear to keep compatibility */ + static int audio_idx[4] = { 0, 2, 4, 5 }; + struct hda_codec *codec; + int c, err; + int num_devs[HDA_PCM_NTYPES]; + + err = snd_hda_build_pcms(chip->bus); + if (err < 0) + return err; + + /* create audio PCMs */ + memset(num_devs, 0, sizeof(num_devs)); + list_for_each_entry(codec, &chip->bus->codec_list, list) { + for (c = 0; c < codec->num_pcms; c++) { + struct hda_pcm *cpcm = &codec->pcm_info[c]; + int type = cpcm->pcm_type; + switch (type) { + case HDA_PCM_TYPE_AUDIO: + if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { + snd_printk(KERN_WARNING + "Too many audio devices\n"); + continue; + } + cpcm->device = audio_idx[num_devs[type]]; + break; + case HDA_PCM_TYPE_SPDIF: + case HDA_PCM_TYPE_HDMI: + case HDA_PCM_TYPE_MODEM: + if (num_devs[type]) { + snd_printk(KERN_WARNING + "%s already defined\n", + dev_name[type]); + continue; + } + cpcm->device = dev_idx[type]; + break; + default: + snd_printk(KERN_WARNING + "Invalid PCM type %d\n", type); + continue; + } + num_devs[type]++; + err = create_codec_pcm(chip, codec, cpcm); + if (err < 0) + return err; + } + } return 0; } @@ -1883,13 +1903,13 @@ static void azx_stop_chip(struct azx *chip) #ifdef CONFIG_SND_HDA_POWER_SAVE /* power-up/down the controller */ -static void azx_power_notify(struct hda_bus *bus) +static void azx_power_notify(struct hda_codec *codec) { - struct azx *chip = bus->private_data; + struct azx *chip = codec->bus->private_data; struct hda_codec *c; int power_on = 0; - list_for_each_entry(c, &bus->codec_list, list) { + list_for_each_entry(c, &codec->bus->codec_list, list) { if (c->power_on) { power_on = 1; break; @@ -1900,19 +1920,6 @@ static void azx_power_notify(struct hda_bus *bus) else if (chip->running && power_save_controller) azx_stop_chip(chip); } - -static int snd_hda_codecs_inuse(struct hda_bus *bus) -{ - struct hda_codec *codec; - - list_for_each_entry(codec, &bus->codec_list, list) { - if (snd_hda_codec_needs_resume(codec)) - return 1; - } - return 0; -} -#else /* !CONFIG_SND_HDA_POWER_SAVE */ -#define snd_hda_codecs_inuse(bus) 1 #endif /* CONFIG_SND_HDA_POWER_SAVE */ #ifdef CONFIG_PM @@ -1944,16 +1951,13 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) return 0; } -static int azx_resume_early(struct pci_dev *pci) -{ - return pci_restore_state(pci); -} - static int azx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "hda-intel: pci_enable_device failed, " "disabling device\n"); @@ -2091,10 +2095,6 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), - /* broken BIOS */ - SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), - /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ - SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), {} }; @@ -2229,7 +2229,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->playback_streams = ATIHDMI_NUM_PLAYBACK; chip->capture_streams = ATIHDMI_NUM_CAPTURE; break; - case AZX_DRIVER_GENERIC: default: chip->playback_streams = ICH6_NUM_PLAYBACK; chip->capture_streams = ICH6_NUM_CAPTURE; @@ -2339,30 +2338,40 @@ static int __devinit azx_probe(struct pci_dev *pci, } err = azx_create(card, pci, dev, pci_id->driver_data, &chip); - if (err < 0) - goto out_free; + if (err < 0) { + snd_card_free(card); + return err; + } card->private_data = chip; /* create codec instances */ err = azx_codec_create(chip, model[dev], probe_mask[dev]); - if (err < 0) - goto out_free; + if (err < 0) { + snd_card_free(card); + return err; + } /* create PCM streams */ - err = snd_hda_build_pcms(chip->bus); - if (err < 0) - goto out_free; + err = azx_pcm_create(chip); + if (err < 0) { + snd_card_free(card); + return err; + } /* create mixer controls */ err = azx_mixer_create(chip); - if (err < 0) - goto out_free; + if (err < 0) { + snd_card_free(card); + return err; + } snd_card_set_dev(card, &pci->dev); err = snd_card_register(card); - if (err < 0) - goto out_free; + if (err < 0) { + snd_card_free(card); + return err; + } pci_set_drvdata(pci, card); chip->running = 1; @@ -2371,9 +2380,6 @@ static int __devinit azx_probe(struct pci_dev *pci, dev++; return err; -out_free: - snd_card_free(card); - return err; } static void __devexit azx_remove(struct pci_dev *pci) @@ -2447,11 +2453,6 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, - /* AMD Generic, PCI class code and Vendor ID for HD Audio */ - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), - .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, - .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); @@ -2464,7 +2465,6 @@ static struct pci_driver driver = { .remove = __devexit_p(azx_remove), #ifdef CONFIG_PM .suspend = azx_suspend, - .resume_early = azx_resume_early, .resume = azx_resume, #endif }; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 6f2fe0f9fdd8..7957fefda730 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -96,8 +96,6 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name); int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves); -void snd_hda_codec_reset(struct hda_codec *codec); -int snd_hda_codec_configure(struct hda_codec *codec); /* amp value bits */ #define HDA_AMP_MUTE 0x80 @@ -284,12 +282,6 @@ int snd_hda_codec_proc_new(struct hda_codec *codec); static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } #endif -#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 -void snd_print_pcm_rates(int pcm, char *buf, int buflen); - -#define SND_PRINT_BITS_ADVISED_BUFSIZE 16 -void snd_print_pcm_bits(int pcm, char *buf, int buflen); - /* * Misc */ @@ -372,17 +364,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) -#define AMP_OUT_MUTE 0xb080 -#define AMP_OUT_UNMUTE 0xb000 -#define AMP_OUT_ZERO 0xb000 +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 /* pinctl values */ #define PIN_IN (AC_PINCTL_IN_EN) -#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) +#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) #define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50) -#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) +#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) #define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80) -#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) -#define PIN_OUT (AC_PINCTL_OUT_EN) +#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) +#define PIN_OUT (AC_PINCTL_OUT_EN) #define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN) #define PIN_HP_AMP (AC_PINCTL_HP_EN) @@ -401,26 +393,10 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); -int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl); -void snd_hda_ctls_clear(struct hda_codec *codec); - /* * hwdep interface */ -#ifdef CONFIG_SND_HDA_HWDEP int snd_hda_create_hwdep(struct hda_codec *codec); -#else -static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } -#endif - -#ifdef CONFIG_SND_HDA_RECONFIG -int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); -#else -static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) -{ - return 0; -} -#endif /* * power-management @@ -454,66 +430,4 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) -/* - * CEA Short Audio Descriptor data - */ -struct cea_sad { - int channels; - int format; /* (format == 0) indicates invalid SAD */ - int rates; - int sample_bits; /* for LPCM */ - int max_bitrate; /* for AC3...ATRAC */ - int profile; /* for WMAPRO */ -}; - -#define ELD_FIXED_BYTES 20 -#define ELD_MAX_MNL 16 -#define ELD_MAX_SAD 16 - -/* - * ELD: EDID Like Data - */ -struct hdmi_eld { - int eld_size; - int baseline_len; - int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ - int cea_edid_ver; - char monitor_name[ELD_MAX_MNL + 1]; - int manufacture_id; - int product_id; - u64 port_id; - int support_hdcp; - int support_ai; - int conn_type; - int aud_synch_delay; - int spk_alloc; - int sad_count; - struct cea_sad sad[ELD_MAX_SAD]; -#ifdef CONFIG_PROC_FS - struct snd_info_entry *proc_entry; -#endif -}; - -int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); -int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); -void snd_hdmi_show_eld(struct hdmi_eld *eld); - -#ifdef CONFIG_PROC_FS -int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); -void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); -#else -static inline int snd_hda_eld_proc_new(struct hda_codec *codec, - struct hdmi_eld *eld) -{ - return 0; -} -static inline void snd_hda_eld_proc_free(struct hda_codec *codec, - struct hdmi_eld *eld) -{ -} -#endif - -#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 -void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); - #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h new file mode 100644 index 000000000000..dfbcfa88da44 --- /dev/null +++ b/sound/pci/hda/hda_patch.h @@ -0,0 +1,22 @@ +/* + * HDA Patches - included by hda_codec.c + */ + +/* Realtek codecs */ +extern struct hda_codec_preset snd_hda_preset_realtek[]; +/* C-Media codecs */ +extern struct hda_codec_preset snd_hda_preset_cmedia[]; +/* Analog Devices codecs */ +extern struct hda_codec_preset snd_hda_preset_analog[]; +/* SigmaTel codecs */ +extern struct hda_codec_preset snd_hda_preset_sigmatel[]; +/* SiLabs 3054/3055 modem codecs */ +extern struct hda_codec_preset snd_hda_preset_si3054[]; +/* ATI HDMI codecs */ +extern struct hda_codec_preset snd_hda_preset_atihdmi[]; +/* Conexant audio codec */ +extern struct hda_codec_preset snd_hda_preset_conexant[]; +/* VIA codecs */ +extern struct hda_codec_preset snd_hda_preset_via[]; +/* NVIDIA HDMI codecs */ +extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 7ca66d654148..c39af986bff1 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -91,21 +91,31 @@ static void print_amp_vals(struct snd_info_buffer *buffer, static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) { - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + static unsigned int rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 384000 + }; + int i; pcm &= AC_SUPPCM_RATES; snd_iprintf(buffer, " rates [0x%x]:", pcm); - snd_print_pcm_rates(pcm, buf, sizeof(buf)); - snd_iprintf(buffer, "%s\n", buf); + for (i = 0; i < ARRAY_SIZE(rates); i++) + if (pcm & (1 << i)) + snd_iprintf(buffer, " %d", rates[i]); + snd_iprintf(buffer, "\n"); } static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { - char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; + static unsigned int bits[] = { 8, 16, 20, 24, 32 }; + int i; - snd_iprintf(buffer, " bits [0x%x]:", (pcm >> 16) & 0xff); - snd_print_pcm_bits(pcm, buf, sizeof(buf)); - snd_iprintf(buffer, "%s\n", buf); + pcm = (pcm >> 16) & 0xff; + snd_iprintf(buffer, " bits [0x%x]:", pcm); + for (i = 0; i < ARRAY_SIZE(bits); i++) + if (pcm & (1 << i)) + snd_iprintf(buffer, " %d", bits[i]); + snd_iprintf(buffer, "\n"); } static void print_pcm_formats(struct snd_info_buffer *buffer, @@ -135,6 +145,32 @@ static void print_pcm_caps(struct snd_info_buffer *buffer, print_pcm_formats(buffer, stream); } +static const char *get_jack_location(u32 cfg) +{ + static char *bases[7] = { + "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", + }; + static unsigned char specials_idx[] = { + 0x07, 0x08, + 0x17, 0x18, 0x19, + 0x37, 0x38 + }; + static char *specials[] = { + "Rear Panel", "Drive Bar", + "Riser", "HDMI", "ATAPI", + "Mobile-In", "Mobile-Out" + }; + int i; + cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; + if ((cfg & 0x0f) < 7) + return bases[cfg & 0x0f]; + for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { + if (cfg == specials_idx[i]) + return specials[i]; + } + return "UNKNOWN"; +} + static const char *get_jack_connection(u32 cfg) { static char *names[16] = { @@ -170,6 +206,13 @@ static void print_pin_caps(struct snd_info_buffer *buffer, int *supports_vref) { static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; + static char *jack_types[16] = { + "Line Out", "Speaker", "HP Out", "CD", + "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", + "Line In", "Aux", "Mic", "Telephony", + "SPDIF In", "Digitial In", "Reserved", "Other" + }; + static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; unsigned int caps, val; caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); @@ -231,9 +274,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer, caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], - snd_hda_get_jack_type(caps), - snd_hda_get_jack_connectivity(caps), - snd_hda_get_jack_location(caps)); + jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], + jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], + get_jack_location(caps)); snd_iprintf(buffer, " Conn = %s, Color = %s\n", get_jack_connection(caps), get_jack_color(caps)); @@ -414,6 +457,17 @@ static void print_conn_list(struct snd_info_buffer *buffer, } } +static void print_realtek_coef(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + int coeff = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); + coeff = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_COEF_INDEX, 0); + snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); +} + static void print_gpio(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -446,13 +500,12 @@ static void print_gpio(struct snd_info_buffer *buffer, for (i = 0; i < max; ++i) snd_iprintf(buffer, " IO[%d]: enable=%d, dir=%d, wake=%d, " - "sticky=%d, data=%d, unsol=%d\n", i, + "sticky=%d, data=%d\n", i, (enable & (1<<i)) ? 1 : 0, (direction & (1<<i)) ? 1 : 0, (wake & (1<<i)) ? 1 : 0, (sticky & (1<<i)) ? 1 : 0, - (data & (1<<i)) ? 1 : 0, - (unsol & (1<<i)) ? 1 : 0); + (data & (1<<i)) ? 1 : 0); /* FIXME: add GPO and GPI pin information */ } @@ -460,11 +513,12 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct hda_codec *codec = entry->private_data; + char buf[32]; hda_nid_t nid; int i, nodes; - snd_iprintf(buffer, "Codec: %s\n", - codec->name ? codec->name : "Not Set"); + snd_hda_get_codec_name(codec, buf, sizeof(buf)); + snd_iprintf(buffer, "Codec: %s\n", buf); snd_iprintf(buffer, "Address: %d\n", codec->addr); snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); @@ -493,8 +547,6 @@ static void print_codec_info(struct snd_info_entry *entry, } print_gpio(buffer, codec, codec->afg); - if (codec->proc_widget_hook) - codec->proc_widget_hook(buffer, codec, codec->afg); for (i = 0; i < nodes; i++, nid++) { unsigned int wid_caps = @@ -597,8 +649,9 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_caps & AC_WCAP_PROC_WID) print_proc_caps(buffer, codec, nid); - if (codec->proc_widget_hook) - codec->proc_widget_hook(buffer, codec, nid); + /* NID 0x20 == Realtek Define Registers */ + if (codec->vendor_id == 0x10ec && nid == 0x20) + print_realtek_coef(buffer, codec, nid); } snd_hda_power_down(codec); } diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index c1918a1a6df9..686c77491dea 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -27,6 +27,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" struct ad198x_spec { struct snd_kcontrol_new *mixers[5]; @@ -66,7 +67,8 @@ struct ad198x_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - struct snd_array kctls; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -152,8 +154,6 @@ static const char *ad_slave_sws[] = { NULL }; -static void ad198x_free_kctls(struct hda_codec *codec); - static int ad198x_build_controls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -202,7 +202,6 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } - ad198x_free_kctls(codec); /* no longer needed */ return 0; } @@ -376,27 +375,16 @@ static int ad198x_build_pcms(struct hda_codec *codec) return 0; } -static void ad198x_free_kctls(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - static void ad198x_free(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; + unsigned int i; - if (!spec) - return; - - ad198x_free_kctls(codec); + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } kfree(codec->spec); } @@ -641,36 +629,6 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "External Amplifier", - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad198x_eapd_put, - .private_value = 0x1b | (1 << 8), /* port-D, inversed */ - }, - { } /* end */ -}; - -static struct snd_kcontrol_new ad1986a_samsung_mixers[] = { - HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), - HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), @@ -959,7 +917,6 @@ enum { AD1986A_LAPTOP_EAPD, AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, - AD1986A_SAMSUNG, AD1986A_MODELS }; @@ -970,7 +927,6 @@ static const char *ad1986a_models[AD1986A_MODELS] = { [AD1986A_LAPTOP_EAPD] = "laptop-eapd", [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", - [AD1986A_SAMSUNG] = "samsung", }; static struct snd_pci_quirk ad1986a_cfg_tbl[] = { @@ -993,9 +949,9 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG), - SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG), - SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), @@ -1077,17 +1033,6 @@ static int patch_ad1986a(struct hda_codec *codec) break; case AD1986A_LAPTOP_EAPD: spec->mixers[0] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_laptop_eapd_capture_source; - break; - case AD1986A_SAMSUNG: - spec->mixers[0] = ad1986a_samsung_mixers; spec->num_init_verbs = 3; spec->init_verbs[1] = ad1986a_eapd_init_verbs; spec->init_verbs[2] = ad1986a_automic_verbs; @@ -2507,6 +2452,9 @@ static struct hda_amp_list ad1988_loopbacks[] = { * Automatic parse of I/O pins from the BIOS configuration */ +#define NUM_CONTROL_ALLOC 32 +#define NUM_VERB_ALLOC 32 + enum { AD_CTL_WIDGET_VOL, AD_CTL_WIDGET_MUTE, @@ -2524,15 +2472,27 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return -ENOMEM; + if (spec->num_kctl_used >= spec->num_kctl_alloc) { + int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; + + knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ + if (! knew) + return -ENOMEM; + if (spec->kctl_alloc) { + memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); + kfree(spec->kctl_alloc); + } + spec->kctl_alloc = knew; + spec->num_kctl_alloc = num; + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; *knew = ad1988_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); if (! knew->name) return -ENOMEM; knew->private_value = val; + spec->num_kctl_used++; return 0; } @@ -2886,8 +2846,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = AD1988_SPDIF_IN; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; @@ -4307,7 +4267,7 @@ static int patch_ad1882(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_analog[] = { +struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, @@ -4325,26 +4285,3 @@ static struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 }, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:11d4*"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Analog Devices HD-audio codec"); - -static struct hda_codec_preset_list analog_list = { - .preset = snd_hda_preset_analog, - .owner = THIS_MODULE, -}; - -static int __init patch_analog_init(void) -{ - return snd_hda_add_codec_preset(&analog_list); -} - -static void __exit patch_analog_exit(void) -{ - snd_hda_delete_codec_preset(&analog_list); -} - -module_init(patch_analog_init) -module_exit(patch_analog_exit) diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 5887b827bb32..ba61575983fd 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -27,6 +27,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" struct atihdmi_spec { struct hda_multi_out multiout; @@ -186,40 +187,13 @@ static int patch_atihdmi(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_atihdmi[] = { +struct hda_codec_preset snd_hda_preset_atihdmi[] = { { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, + { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi }, { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:1002793c"); -MODULE_ALIAS("snd-hda-codec-id:10027919"); -MODULE_ALIAS("snd-hda-codec-id:1002791a"); -MODULE_ALIAS("snd-hda-codec-id:1002aa01"); -MODULE_ALIAS("snd-hda-codec-id:10951390"); -MODULE_ALIAS("snd-hda-codec-id:17e80047"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ATI HDMI HD-audio codec"); - -static struct hda_codec_preset_list atihdmi_list = { - .preset = snd_hda_preset_atihdmi, - .owner = THIS_MODULE, -}; - -static int __init patch_atihdmi_init(void) -{ - return snd_hda_add_codec_preset(&atihdmi_list); -} - -static void __exit patch_atihdmi_exit(void) -{ - snd_hda_delete_codec_preset(&atihdmi_list); -} - -module_init(patch_atihdmi_init) -module_exit(patch_atihdmi_exit) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index f3ebe837f2d5..6ef57fbfb6eb 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -28,6 +28,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" #define NUM_PINS 11 @@ -735,32 +736,8 @@ static int patch_cmi9880(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_cmedia[] = { +struct hda_codec_preset snd_hda_preset_cmedia[] = { { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:13f69880"); -MODULE_ALIAS("snd-hda-codec-id:434d4980"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("C-Media HD-audio codec"); - -static struct hda_codec_preset_list cmedia_list = { - .preset = snd_hda_preset_cmedia, - .owner = THIS_MODULE, -}; - -static int __init patch_cmedia_init(void) -{ - return snd_hda_add_codec_preset(&cmedia_list); -} - -static void __exit patch_cmedia_exit(void) -{ - snd_hda_delete_codec_preset(&cmedia_list); -} - -module_init(patch_cmedia_init) -module_exit(patch_cmedia_exit) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index b20e1cede00b..7c1eb23f0cec 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,6 +27,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -85,6 +86,8 @@ struct conexant_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -341,6 +344,15 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { + struct conexant_spec *spec = codec->spec; + unsigned int i; + + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } + kfree(codec->spec); } @@ -1770,7 +1782,7 @@ static int patch_cxt5051(struct hda_codec *codec) /* */ -static struct hda_codec_preset snd_hda_preset_conexant[] = { +struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", .patch = patch_cxt5045 }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", @@ -1779,28 +1791,3 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5051 }, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:14f15045"); -MODULE_ALIAS("snd-hda-codec-id:14f15047"); -MODULE_ALIAS("snd-hda-codec-id:14f15051"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Conexant HD-audio codec"); - -static struct hda_codec_preset_list conexant_list = { - .preset = snd_hda_preset_conexant, - .owner = THIS_MODULE, -}; - -static int __init patch_conexant_init(void) -{ - return snd_hda_add_codec_preset(&conexant_list); -} - -static void __exit patch_conexant_exit(void) -{ - snd_hda_delete_codec_preset(&conexant_list); -} - -module_init(patch_conexant_init) -module_exit(patch_conexant_exit) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c deleted file mode 100644 index 290da562f29b..000000000000 --- a/sound/pci/hda/patch_intelhdmi.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * - * patch_intelhdmi.c - Patch for Intel HDMI codecs - * - * Copyright(c) 2008 Intel Corporation. All rights reserved. - * - * Authors: - * Jiang Zhe <zhe.jiang@intel.com> - * Wu Fengguang <wfg@linux.intel.com> - * - * Maintained by: - * Wu Fengguang <wfg@linux.intel.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <sound/core.h> -#include "hda_codec.h" -#include "hda_local.h" - -#define CVT_NID 0x02 /* audio converter */ -#define PIN_NID 0x03 /* HDMI output pin */ - -#define INTEL_HDMI_EVENT_TAG 0x08 - -struct intel_hdmi_spec { - struct hda_multi_out multiout; - struct hda_pcm pcm_rec; - struct hdmi_eld sink_eld; -}; - -static struct hda_verb pinout_enable_verb[] = { - {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {} /* terminator */ -}; - -static struct hda_verb pinout_disable_verb[] = { - {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, - {} -}; - -static struct hda_verb unsolicited_response_verb[] = { - {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | - INTEL_HDMI_EVENT_TAG}, - {} -}; - -static struct hda_verb def_chan_map[] = { - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, - {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, - {} -}; - - -struct hdmi_audio_infoframe { - u8 type; /* 0x84 */ - u8 ver; /* 0x01 */ - u8 len; /* 0x0a */ - - u8 checksum; /* PB0 */ - u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ - u8 SS01_SF24; - u8 CXT04; - u8 CA; - u8 LFEPBL01_LSV36_DM_INH7; - u8 reserved[5]; /* PB6 - PB10 */ -}; - -/* - * CEA speaker placement: - * - * FLH FCH FRH - * FLW FL FLC FC FRC FR FRW - * - * LFE - * TC - * - * RL RLC RC RRC RR - * - * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to - * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. - */ -enum cea_speaker_placement { - FL = (1 << 0), /* Front Left */ - FC = (1 << 1), /* Front Center */ - FR = (1 << 2), /* Front Right */ - FLC = (1 << 3), /* Front Left Center */ - FRC = (1 << 4), /* Front Right Center */ - RL = (1 << 5), /* Rear Left */ - RC = (1 << 6), /* Rear Center */ - RR = (1 << 7), /* Rear Right */ - RLC = (1 << 8), /* Rear Left Center */ - RRC = (1 << 9), /* Rear Right Center */ - LFE = (1 << 10), /* Low Frequency Effect */ - FLW = (1 << 11), /* Front Left Wide */ - FRW = (1 << 12), /* Front Right Wide */ - FLH = (1 << 13), /* Front Left High */ - FCH = (1 << 14), /* Front Center High */ - FRH = (1 << 15), /* Front Right High */ - TC = (1 << 16), /* Top Center */ -}; - -/* - * ELD SA bits in the CEA Speaker Allocation data block - */ -static int eld_speaker_allocation_bits[] = { - [0] = FL | FR, - [1] = LFE, - [2] = FC, - [3] = RL | RR, - [4] = RC, - [5] = FLC | FRC, - [6] = RLC | RRC, - /* the following are not defined in ELD yet */ - [7] = FLW | FRW, - [8] = FLH | FRH, - [9] = TC, - [10] = FCH, -}; - -struct cea_channel_speaker_allocation { - int ca_index; - int speakers[8]; - - /* derived values, just for convenience */ - int channels; - int spk_mask; -}; - -/* - * This is an ordered list! - * - * The preceding ones have better chances to be selected by - * hdmi_setup_channel_allocation(). - */ -static struct cea_channel_speaker_allocation channel_allocations[] = { -/* channel: 8 7 6 5 4 3 2 1 */ -{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, - /* 2.1 */ -{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, - /* Dolby Surround */ -{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, -{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, -{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, -{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, -{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, -{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, - /* 5.1 */ -{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, - /* 6.1 */ -{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, - /* 7.1 */ -{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, -{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, -{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, -{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, -{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, -{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, -{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, -{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, -}; - -/* - * HDMI routines - */ - -#ifdef BE_PARANOID -static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, - int *packet_index, int *byte_index) -{ - int val; - - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); - - *packet_index = val >> 5; - *byte_index = val & 0x1f; -} -#endif - -static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, - int packet_index, int byte_index) -{ - int val; - - val = (packet_index << 5) | (byte_index & 0x1f); - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); -} - -static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, - unsigned char val) -{ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); -} - -static void hdmi_enable_output(struct hda_codec *codec) -{ - /* Enable Audio InfoFrame Transmission */ - hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); - snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, - AC_DIPXMIT_BEST); - /* Unmute */ - if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, PIN_NID, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Enable pin out */ - snd_hda_sequence_write(codec, pinout_enable_verb); -} - -static void hdmi_disable_output(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, pinout_disable_verb); - if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, PIN_NID, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - /* - * FIXME: noises may arise when playing music after reloading the - * kernel module, until the next X restart or monitor repower. - */ -} - -static int hdmi_get_channel_count(struct hda_codec *codec) -{ - return 1 + snd_hda_codec_read(codec, CVT_NID, 0, - AC_VERB_GET_CVT_CHAN_COUNT, 0); -} - -static void hdmi_set_channel_count(struct hda_codec *codec, int chs) -{ - snd_hda_codec_write(codec, CVT_NID, 0, - AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); - - if (chs != hdmi_get_channel_count(codec)) - snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", - chs, hdmi_get_channel_count(codec)); -} - -static void hdmi_debug_channel_mapping(struct hda_codec *codec) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int i; - int slot; - - for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, CVT_NID, 0, - AC_VERB_GET_HDMI_CHAN_SLOT, i); - printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", - slot >> 4, slot & 0x7); - } -#endif -} - -static void hdmi_parse_eld(struct hda_codec *codec) -{ - struct intel_hdmi_spec *spec = codec->spec; - struct hdmi_eld *eld = &spec->sink_eld; - - if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) - snd_hdmi_show_eld(eld); -} - - -/* - * Audio InfoFrame routines - */ - -static void hdmi_debug_dip_size(struct hda_codec *codec) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int i; - int size; - - size = snd_hdmi_get_eld_size(codec, PIN_NID); - printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); - - for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, PIN_NID, 0, - AC_VERB_GET_HDMI_DIP_SIZE, i); - printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); - } -#endif -} - -static void hdmi_clear_dip_buffers(struct hda_codec *codec) -{ -#ifdef BE_PARANOID - int i, j; - int size; - int pi, bi; - for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, PIN_NID, 0, - AC_VERB_GET_HDMI_DIP_SIZE, i); - if (size == 0) - continue; - - hdmi_set_dip_index(codec, PIN_NID, i, 0x0); - for (j = 1; j < 1000; j++) { - hdmi_write_dip_byte(codec, PIN_NID, 0x0); - hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); - if (pi != i) - snd_printd(KERN_INFO "dip index %d: %d != %d\n", - bi, pi, i); - if (bi == 0) /* byte index wrapped around */ - break; - } - snd_printd(KERN_INFO - "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", - i, size, j); - } -#endif -} - -static void hdmi_fill_audio_infoframe(struct hda_codec *codec, - struct hdmi_audio_infoframe *ai) -{ - u8 *params = (u8 *)ai; - int i; - - hdmi_debug_dip_size(codec); - hdmi_clear_dip_buffers(codec); /* be paranoid */ - - hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); - for (i = 0; i < sizeof(ai); i++) - hdmi_write_dip_byte(codec, PIN_NID, params[i]); -} - -/* - * Compute derived values in channel_allocations[]. - */ -static void init_channel_allocations(void) -{ - int i, j; - struct cea_channel_speaker_allocation *p; - - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - p = channel_allocations + i; - p->channels = 0; - p->spk_mask = 0; - for (j = 0; j < ARRAY_SIZE(p->speakers); j++) - if (p->speakers[j]) { - p->channels++; - p->spk_mask |= p->speakers[j]; - } - } -} - -/* - * The transformation takes two steps: - * - * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask - * spk_mask => (channel_allocations[]) => ai->CA - * - * TODO: it could select the wrong CA from multiple candidates. -*/ -static int hdmi_setup_channel_allocation(struct hda_codec *codec, - struct hdmi_audio_infoframe *ai) -{ - struct intel_hdmi_spec *spec = codec->spec; - struct hdmi_eld *eld = &spec->sink_eld; - int i; - int spk_mask = 0; - int channels = 1 + (ai->CC02_CT47 & 0x7); - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - - /* - * CA defaults to 0 for basic stereo audio - */ - if (!eld->eld_ver) - return 0; - if (!eld->spk_alloc) - return 0; - if (channels <= 2) - return 0; - - /* - * expand ELD's speaker allocation mask - * - * ELD tells the speaker mask in a compact(paired) form, - * expand ELD's notions to match the ones used by Audio InfoFrame. - */ - for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (eld->spk_alloc & (1 << i)) - spk_mask |= eld_speaker_allocation_bits[i]; - } - - /* search for the first working match in the CA table */ - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - if (channels == channel_allocations[i].channels && - (spk_mask & channel_allocations[i].spk_mask) == - channel_allocations[i].spk_mask) { - ai->CA = channel_allocations[i].ca_index; - break; - } - } - - snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); - snd_printdd(KERN_INFO - "HDMI: select CA 0x%x for %d-channel allocation: %s\n", - ai->CA, channels, buf); - - return ai->CA; -} - -static void hdmi_setup_channel_mapping(struct hda_codec *codec, - struct hdmi_audio_infoframe *ai) -{ - if (!ai->CA) - return; - - /* - * TODO: adjust channel mapping if necessary - * ALSA sequence is front/surr/clfe/side? - */ - - snd_hda_sequence_write(codec, def_chan_map); - hdmi_debug_channel_mapping(codec); -} - - -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_audio_infoframe ai = { - .type = 0x84, - .ver = 0x01, - .len = 0x0a, - .CC02_CT47 = substream->runtime->channels - 1, - }; - - hdmi_setup_channel_allocation(codec, &ai); - hdmi_setup_channel_mapping(codec, &ai); - - hdmi_fill_audio_infoframe(codec, &ai); -} - - -/* - * Unsolicited events - */ - -static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) -{ - int pind = !!(res & AC_UNSOL_RES_PD); - int eldv = !!(res & AC_UNSOL_RES_ELDV); - - printk(KERN_INFO - "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", - pind, eldv); - - if (pind && eldv) { - hdmi_parse_eld(codec); - /* TODO: do real things about ELD */ - } -} - -static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) -{ - int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; - int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); - int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); - - printk(KERN_INFO - "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", - subtag, - cp_state, - cp_ready); - - /* TODO */ - if (cp_state) - ; - if (cp_ready) - ; -} - - -static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) -{ - int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; - - if (tag != INTEL_HDMI_EVENT_TAG) { - snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); - return; - } - - if (subtag == 0) - hdmi_intrinsic_event(codec, res); - else - hdmi_non_intrinsic_event(codec, res); -} - -/* - * Callbacks - */ - -static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct intel_hdmi_spec *spec = codec->spec; - - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct intel_hdmi_spec *spec = codec->spec; - - hdmi_disable_output(codec); - - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct intel_hdmi_spec *spec = codec->spec; - - snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); - - hdmi_set_channel_count(codec, substream->runtime->channels); - - hdmi_setup_audio_infoframe(codec, substream); - - hdmi_enable_output(codec); - - return 0; -} - -static struct hda_pcm_stream intel_hdmi_pcm_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = CVT_NID, /* NID to query formats and rates and setup streams */ - .ops = { - .open = intel_hdmi_playback_pcm_open, - .close = intel_hdmi_playback_pcm_close, - .prepare = intel_hdmi_playback_pcm_prepare - }, -}; - -static int intel_hdmi_build_pcms(struct hda_codec *codec) -{ - struct intel_hdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "INTEL HDMI"; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; - - return 0; -} - -static int intel_hdmi_build_controls(struct hda_codec *codec) -{ - struct intel_hdmi_spec *spec = codec->spec; - int err; - - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; - - return 0; -} - -static int intel_hdmi_init(struct hda_codec *codec) -{ - /* disable audio output as early as possible */ - hdmi_disable_output(codec); - - snd_hda_sequence_write(codec, unsolicited_response_verb); - - return 0; -} - -static void intel_hdmi_free(struct hda_codec *codec) -{ - struct intel_hdmi_spec *spec = codec->spec; - - snd_hda_eld_proc_free(codec, &spec->sink_eld); - kfree(spec); -} - -static struct hda_codec_ops intel_hdmi_patch_ops = { - .init = intel_hdmi_init, - .free = intel_hdmi_free, - .build_pcms = intel_hdmi_build_pcms, - .build_controls = intel_hdmi_build_controls, - .unsol_event = intel_hdmi_unsol_event, -}; - -static int patch_intel_hdmi(struct hda_codec *codec) -{ - struct intel_hdmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = CVT_NID; - - codec->spec = spec; - codec->patch_ops = intel_hdmi_patch_ops; - - snd_hda_eld_proc_new(codec, &spec->sink_eld); - - init_channel_allocations(); - - return 0; -} - -static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { - { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, - { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, - { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, - { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, - { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:808629fb"); -MODULE_ALIAS("snd-hda-codec-id:80862801"); -MODULE_ALIAS("snd-hda-codec-id:80862802"); -MODULE_ALIAS("snd-hda-codec-id:80862803"); -MODULE_ALIAS("snd-hda-codec-id:10951392"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Intel HDMI HD-audio codec"); - -static struct hda_codec_preset_list intel_list = { - .preset = snd_hda_preset_intelhdmi, - .owner = THIS_MODULE, -}; - -static int __init patch_intelhdmi_init(void) -{ - return snd_hda_add_codec_preset(&intel_list); -} - -static void __exit patch_intelhdmi_exit(void) -{ - snd_hda_delete_codec_preset(&intel_list); -} - -module_init(patch_intelhdmi_init) -module_exit(patch_intelhdmi_exit) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 0cd53063e62e..2eed2c8b98da 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -158,34 +158,8 @@ static int patch_nvhdmi(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { +struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0067, .name = "NVIDIA MCP67 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:10de0002"); -MODULE_ALIAS("snd-hda-codec-id:10de0007"); -MODULE_ALIAS("snd-hda-codec-id:10de0067"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); - -static struct hda_codec_preset_list nvhdmi_list = { - .preset = snd_hda_preset_nvhdmi, - .owner = THIS_MODULE, -}; - -static int __init patch_nvhdmi_init(void) -{ - return snd_hda_add_codec_preset(&nvhdmi_list); -} - -static void __exit patch_nvhdmi_exit(void) -{ - snd_hda_delete_codec_preset(&nvhdmi_list); -} - -module_init(patch_nvhdmi_init) -module_exit(patch_nvhdmi_exit) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0bd4e6bf354d..a378c0145125 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -30,6 +30,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" #define ALC880_FRONT_EVENT 0x01 #define ALC880_DCVOL_EVENT 0x02 @@ -113,7 +114,6 @@ enum { ALC268_3ST, ALC268_TOSHIBA, ALC268_ACER, - ALC268_ACER_DMIC, ALC268_ACER_ASPIRE_ONE, ALC268_DELL, ALC268_ZEPTO, @@ -130,8 +130,6 @@ enum { ALC269_QUANTA_FL1, ALC269_ASUS_EEEPC_P703, ALC269_ASUS_EEEPC_P901, - ALC269_FUJITSU, - ALC269_LIFEBOOK, ALC269_AUTO, ALC269_MODEL_LAST /* last tag */ }; @@ -154,7 +152,6 @@ enum { enum { ALC660VD_3ST, ALC660VD_3ST_DIG, - ALC660VD_ASUS_V1S, ALC861VD_3ST, ALC861VD_3ST_DIG, ALC861VD_6ST_DIG, @@ -215,7 +212,6 @@ enum { ALC883_TARGA_2ch_DIG, ALC883_ACER, ALC883_ACER_ASPIRE, - ALC888_ACER_ASPIRE_4930G, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, @@ -229,11 +225,9 @@ enum { ALC883_MITAC, ALC883_CLEVO_M720, ALC883_FUJITSU_PI2515, - ALC888_FUJITSU_XA3530, ALC883_3ST_6ch_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, - ALC1200_ASUS_P5Q, ALC883_AUTO, ALC883_MODEL_LAST, }; @@ -245,7 +239,6 @@ struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; - struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -275,7 +268,6 @@ struct alc_spec { hda_nid_t *adc_nids; hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ - unsigned char is_mix_capture; /* matrix-style capture (non-mux) */ /* capture source */ unsigned int num_mux_defs; @@ -292,7 +284,8 @@ struct alc_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - struct snd_array kctls; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -330,7 +323,6 @@ struct alc_config_preset { struct snd_kcontrol_new *mixers[5]; /* should be identical size * with spec */ - struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; unsigned int num_dacs; hda_nid_t *dac_nids; @@ -383,40 +375,15 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned int mux_idx; + unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; hda_nid_t nid = spec->capsrc_nids ? spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - - mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; - imux = &spec->input_mux[mux_idx]; - - if (spec->is_mix_capture) { - /* Matrix-mixer style (e.g. ALC882) */ - unsigned int *cur_val = &spec->cur_mux[adc_idx]; - unsigned int i, idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx) - return 0; - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, - imux->items[i].index, - HDA_AMP_MUTE, v); - } - *cur_val = idx; - return 1; - } else { - /* MUX style (e.g. ALC880) */ - return snd_hda_input_mux_put(codec, imux, ucontrol, nid, - &spec->cur_mux[adc_idx]); - } + return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol, + nid, &spec->cur_mux[adc_idx]); } + /* * channel mode setting */ @@ -750,43 +717,6 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, #endif /* CONFIG_SND_DEBUG */ /* - */ -static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix) -{ - if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers))) - return; - spec->mixers[spec->num_mixers++] = mix; -} - -static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) -{ - if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs))) - return; - spec->init_verbs[spec->num_init_verbs++] = verb; -} - -#ifdef CONFIG_PROC_FS -/* - * hook for proc - */ -static void print_realtek_coef(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - int coeff; - - if (nid != 0x20) - return; - coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); - snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); - coeff = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_COEF_INDEX, 0); - snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); -} -#else -#define print_realtek_coef NULL -#endif - -/* * set up from the preset table */ static void setup_preset(struct alc_spec *spec, @@ -795,11 +725,11 @@ static void setup_preset(struct alc_spec *spec, int i; for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) - add_mixer(spec, preset->mixers[i]); - spec->cap_mixer = preset->cap_mixer; + spec->mixers[spec->num_mixers++] = preset->mixers[i]; for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++) - add_verb(spec, preset->init_verbs[i]); + spec->init_verbs[spec->num_init_verbs++] = + preset->init_verbs[i]; spec->channel_mode = preset->channel_mode; spec->num_channel_mode = preset->num_channel_mode; @@ -1177,226 +1107,6 @@ static void alc_fix_pincfg(struct hda_codec *codec, } /* - * ALC888 - */ - -/* - * 2ch mode - */ -static struct hda_verb alc888_4ST_ch2_intel_init[] = { -/* Mic-in jack as mic in */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-in jack as Line in */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-Out as Front */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* - * 4ch mode - */ -static struct hda_verb alc888_4ST_ch4_intel_init[] = { -/* Mic-in jack as mic in */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as Front */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } /* end */ -}; - -/* - * 6ch mode - */ -static struct hda_verb alc888_4ST_ch6_intel_init[] = { -/* Mic-in jack as CLFE */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - { } /* end */ -}; - -/* - * 8ch mode - */ -static struct hda_verb alc888_4ST_ch8_intel_init[] = { -/* Mic-in jack as CLFE */ - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-in jack as Surround */ - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, -/* Line-Out as Side */ - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - { } /* end */ -}; - -static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { - { 2, alc888_4ST_ch2_intel_init }, - { 4, alc888_4ST_ch4_intel_init }, - { 6, alc888_4ST_ch6_intel_init }, - { 8, alc888_4ST_ch8_intel_init }, -}; - -/* - * ALC888 Fujitsu Siemens Amillo xa3530 - */ - -static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Connect Internal HP to Front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Bass HP to Front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Line-Out side jack (SPDIF) to Side */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, -/* Connect Mic jack to CLFE */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect Line-in jack to Surround */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect HP out jack to Front */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Enable unsolicited event for HP jack and Line-out jack */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - {} -}; - -static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned int bits; - /* Line out presence */ - present = snd_hda_codec_read(codec, 0x17, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - /* HP out presence */ - present = present || snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - /* Toggle internal speakers muting */ - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); - /* Toggle internal bass muting */ - snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if (res >> 26 == ALC880_HP_EVENT) - alc888_fujitsu_xa3530_automute(codec); -} - - -/* - * ALC888 Acer Aspire 4930G model - */ - -static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, -/* Connect Internal HP to front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect HP out to front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } -}; - -static struct hda_input_mux alc888_2_capture_sources[2] = { - /* Front mic only available on one ADC */ - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Front Mic", 0xb }, - }, - }, - { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, - } -}; - -static struct snd_kcontrol_new alc888_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, - HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - { } /* end */ -}; - -static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned int bits; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, bits); -} - -static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if (res >> 26 == ALC880_HP_EVENT) - alc888_acer_aspire_4930g_automute(codec); -} - -/* * ALC880 3-stack model * * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e) @@ -1495,126 +1205,49 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = { }; /* capture mixer elements */ -static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int err; - - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, - HDA_INPUT); - err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ - return err; -} - -static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int err; - - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, - HDA_INPUT); - err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ - return err; -} - -typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol, - getput_call_t func) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - int err; - - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ - return err; -} - -static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_get); -} +static struct snd_kcontrol_new alc880_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 3, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; -static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_put); -} +/* capture mixer elements (in case NID 0x07 not available) */ +static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; -/* capture mixer elements */ -#define alc_cap_sw_info snd_ctl_boolean_stereo_info - -static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_get); -} - -static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_put); -} - -#define DEFINE_CAPMIX(num) \ -static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Switch", \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .count = num, \ - .info = alc_cap_sw_info, \ - .get = alc_cap_sw_get, \ - .put = alc_cap_sw_put, \ - }, \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Volume", \ - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ - .count = num, \ - .info = alc_cap_vol_info, \ - .get = alc_cap_vol_get, \ - .put = alc_cap_vol_put, \ - .tlv = { .c = alc_cap_vol_tlv }, \ - }, \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - /* .name = "Capture Source", */ \ - .name = "Input Source", \ - .count = num, \ - .info = alc_mux_enum_info, \ - .get = alc_mux_enum_get, \ - .put = alc_mux_enum_put, \ - }, \ - { } /* end */ \ -} - -/* up to three ADCs */ -DEFINE_CAPMIX(1); -DEFINE_CAPMIX(2); -DEFINE_CAPMIX(3); /* @@ -1900,6 +1533,18 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, { } /* end */ }; @@ -1974,7 +1619,6 @@ static const char *alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", - "PCM Playback Volume", NULL, }; @@ -1994,9 +1638,6 @@ static const char *alc_slave_sws[] = { /* * build control elements */ - -static void alc_free_kctls(struct hda_codec *codec); - static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -2008,11 +1649,7 @@ static int alc_build_controls(struct hda_codec *codec) if (err < 0) return err; } - if (spec->cap_mixer) { - err = snd_hda_add_new_ctls(codec, spec->cap_mixer); - if (err < 0) - return err; - } + if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); @@ -2047,7 +1684,6 @@ static int alc_build_controls(struct hda_codec *codec) return err; } - alc_free_kctls(codec); /* no longer needed */ return 0; } @@ -3138,27 +2774,19 @@ static int alc_build_pcms(struct hda_codec *codec) return 0; } -static void alc_free_kctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - static void alc_free(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + unsigned int i; if (!spec) return; - alc_free_kctls(codec); + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } kfree(spec); codec->spec = NULL; /* to be sure */ } @@ -3640,8 +3268,6 @@ static struct alc_config_preset alc880_presets[] = { alc880_gpio2_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, - .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ - .num_adc_nids = 1, /* single ADC */ .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), .channel_mode = alc880_2_jack_modes, @@ -3906,6 +3532,9 @@ static struct alc_config_preset alc880_presets[] = { * Automatic parse of I/O pins from the BIOS configuration */ +#define NUM_CONTROL_ALLOC 32 +#define NUM_VERB_ALLOC 32 + enum { ALC_CTL_WIDGET_VOL, ALC_CTL_WIDGET_MUTE, @@ -3923,15 +3552,29 @@ static int add_control(struct alc_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return -ENOMEM; + if (spec->num_kctl_used >= spec->num_kctl_alloc) { + int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; + + /* array + terminator */ + knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); + if (!knew) + return -ENOMEM; + if (spec->kctl_alloc) { + memcpy(knew, spec->kctl_alloc, + sizeof(*knew) * spec->num_kctl_alloc); + kfree(spec->kctl_alloc); + } + spec->kctl_alloc = knew; + spec->num_kctl_alloc = num; + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; *knew = alc880_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; knew->private_value = val; + spec->num_kctl_used++; return 0; } @@ -4255,10 +3898,10 @@ static int alc880_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC880_DIGIN_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - add_verb(spec, alc880_volume_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -4282,17 +3925,6 @@ static void alc880_auto_init(struct hda_codec *codec) * OK, here we have finally the patch for ALC880 */ -static void set_capture_mixer(struct alc_spec *spec) -{ - static struct snd_kcontrol_new *caps[3] = { - alc_capture_mixer1, - alc_capture_mixer2, - alc_capture_mixer3, - }; - if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) - spec->cap_mixer = caps[spec->num_adc_nids - 1]; -} - static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; @@ -4348,12 +3980,16 @@ static int patch_alc880(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN) { spec->adc_nids = alc880_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); + spec->mixers[spec->num_mixers] = + alc880_capture_alt_mixer; + spec->num_mixers++; } else { spec->adc_nids = alc880_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); + spec->mixers[spec->num_mixers] = alc880_capture_mixer; + spec->num_mixers++; } } - set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -4364,7 +4000,6 @@ static int patch_alc880(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc880_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -4389,6 +4024,11 @@ static hda_nid_t alc260_adc_nids_alt[1] = { 0x05, }; +static hda_nid_t alc260_hp_adc_nids[2] = { + /* ADC1, 0 */ + 0x05, 0x04 +}; + /* NIDs used when simultaneous access to both ADCs makes sense. Note that * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. */ @@ -4517,13 +4157,13 @@ static void alc260_hp_master_update(struct hda_codec *codec, struct alc_spec *spec = codec->spec; unsigned int val = spec->master_sw ? PIN_HP : 0; /* change HP and line-out pins */ - snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); - snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); /* mono (speaker) depending on the HP jack sense */ val = (val && !spec->jack_present) ? PIN_OUT : 0; - snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } @@ -4602,7 +4242,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, - .private_value = (0x15 << 16) | (0x10 << 8) | 0x11 + .private_value = (0x10 << 16) | (0x15 << 8) | 0x11 }, HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), @@ -4655,7 +4295,7 @@ static void alc260_hp_3013_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; - alc260_hp_master_update(codec, 0x15, 0x10, 0x11); + alc260_hp_master_update(codec, 0x10, 0x15, 0x11); } static void alc260_hp_3013_unsol_event(struct hda_codec *codec, @@ -4787,6 +4427,45 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { { } /* end */ }; +/* capture mixer elements */ +static struct snd_kcontrol_new alc260_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + +static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + /* * initialization verbs */ @@ -5603,6 +5282,7 @@ static struct hda_verb alc260_volume_init_verbs[] = { static int alc260_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + unsigned int wcap; int err; static hda_nid_t alc260_ignore[] = { 0x17, 0 }; @@ -5613,7 +5293,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - if (!spec->kctls.list) + if (!spec->kctl_alloc) return 0; /* can't find valid BIOS pin config */ err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg); if (err < 0) @@ -5623,14 +5303,28 @@ static int alc260_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - add_verb(spec, alc260_volume_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + /* check whether NID 0x04 is valid */ + wcap = get_wcaps(codec, 0x04); + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ + if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + spec->adc_nids = alc260_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); + spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer; + } else { + spec->adc_nids = alc260_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); + spec->mixers[spec->num_mixers] = alc260_capture_mixer; + } + spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -5700,11 +5394,12 @@ static struct alc_config_preset alc260_presets[] = { [ALC260_BASIC] = { .mixers = { alc260_base_output_mixer, alc260_input_mixer, - alc260_pc_beep_mixer }, + alc260_pc_beep_mixer, + alc260_capture_mixer }, .init_verbs = { alc260_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), .adc_nids = alc260_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, @@ -5712,13 +5407,14 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP] = { .mixers = { alc260_hp_output_mixer, - alc260_input_mixer }, + alc260_input_mixer, + alc260_capture_alt_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), + .adc_nids = alc260_hp_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5727,13 +5423,14 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP_DC7600] = { .mixers = { alc260_hp_dc7600_mixer, - alc260_input_mixer }, + alc260_input_mixer, + alc260_capture_alt_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_dc7600_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), + .adc_nids = alc260_hp_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5742,13 +5439,14 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP_3013] = { .mixers = { alc260_hp_3013_mixer, - alc260_input_mixer }, + alc260_input_mixer, + alc260_capture_alt_mixer }, .init_verbs = { alc260_hp_3013_init_verbs, alc260_hp_3013_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), - .adc_nids = alc260_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), + .adc_nids = alc260_hp_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5756,7 +5454,8 @@ static struct alc_config_preset alc260_presets[] = { .init_hook = alc260_hp_3013_automute, }, [ALC260_FUJITSU_S702X] = { - .mixers = { alc260_fujitsu_mixer }, + .mixers = { alc260_fujitsu_mixer, + alc260_capture_mixer }, .init_verbs = { alc260_fujitsu_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5768,7 +5467,8 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = alc260_fujitsu_capture_sources, }, [ALC260_ACER] = { - .mixers = { alc260_acer_mixer }, + .mixers = { alc260_acer_mixer, + alc260_capture_mixer }, .init_verbs = { alc260_acer_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5780,7 +5480,8 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = alc260_acer_capture_sources, }, [ALC260_WILL] = { - .mixers = { alc260_will_mixer }, + .mixers = { alc260_will_mixer, + alc260_capture_mixer }, .init_verbs = { alc260_init_verbs, alc260_will_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5792,7 +5493,8 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = &alc260_capture_source, }, [ALC260_REPLACER_672V] = { - .mixers = { alc260_replacer_672v_mixer }, + .mixers = { alc260_replacer_672v_mixer, + alc260_capture_mixer }, .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5807,7 +5509,8 @@ static struct alc_config_preset alc260_presets[] = { }, #ifdef CONFIG_SND_DEBUG [ALC260_TEST] = { - .mixers = { alc260_test_mixer }, + .mixers = { alc260_test_mixer, + alc260_capture_mixer }, .init_verbs = { alc260_test_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), .dac_nids = alc260_test_dac_nids, @@ -5866,21 +5569,6 @@ static int patch_alc260(struct hda_codec *codec) spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; - if (!spec->adc_nids && spec->input_mux) { - /* check whether NID 0x04 is valid */ - unsigned int wcap = get_wcaps(codec, 0x04); - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - /* get type */ - if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { - spec->adc_nids = alc260_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); - } else { - spec->adc_nids = alc260_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - } - } - set_capture_mixer(spec); - spec->vmaster_nid = 0x08; codec->patch_ops = alc_patch_ops; @@ -5890,7 +5578,6 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc260_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -5938,6 +5625,36 @@ static struct hda_input_mux alc882_capture_source = { { "CD", 0x4 }, }, }; +#define alc882_mux_enum_info alc_mux_enum_info +#define alc882_mux_enum_get alc_mux_enum_get + +static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + const struct hda_input_mux *imux = spec->input_mux; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + hda_nid_t nid = spec->capsrc_nids ? + spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; + unsigned int *cur_val = &spec->cur_mux[adc_idx]; + unsigned int i, idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (*cur_val == idx) + return 0; + for (i = 0; i < imux->num_items; i++) { + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); + } + *cur_val = idx; + return 1; +} + /* * 2ch mode */ @@ -6620,6 +6337,49 @@ static struct hda_verb alc882_auto_init_verbs[] = { { } }; +/* capture mixer elements */ +static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc882_mux_enum_info, + .get = alc882_mux_enum_get, + .put = alc882_mux_enum_put, + }, + { } /* end */ +}; + +static struct snd_kcontrol_new alc882_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 3, + .info = alc882_mux_enum_info, + .get = alc882_mux_enum_get, + .put = alc882_mux_enum_put, + }, + { } /* end */ +}; + #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc882_loopbacks alc880_loopbacks #endif @@ -6748,7 +6508,8 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { - .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, + .mixers = { alc882_targa_mixer, alc882_chmode_mixer, + alc882_capture_mixer }, .init_verbs = { alc882_init_verbs, alc882_targa_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, @@ -6764,7 +6525,8 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc882_targa_automute, }, [ALC882_ASUS_A7J] = { - .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, + .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer, + alc882_capture_mixer }, .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, @@ -7069,7 +6831,6 @@ static int patch_alc882(struct hda_codec *codec) spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; - spec->is_mix_capture = 1; /* matrix-style capture */ if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -7079,13 +6840,17 @@ static int patch_alc882(struct hda_codec *codec) spec->adc_nids = alc882_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); spec->capsrc_nids = alc882_capsrc_nids_alt; + spec->mixers[spec->num_mixers] = + alc882_capture_alt_mixer; + spec->num_mixers++; } else { spec->adc_nids = alc882_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); spec->capsrc_nids = alc882_capsrc_nids; + spec->mixers[spec->num_mixers] = alc882_capture_mixer; + spec->num_mixers++; } } - set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -7096,7 +6861,6 @@ static int patch_alc882(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc882_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -7115,8 +6879,6 @@ static int patch_alc882(struct hda_codec *codec) #define ALC883_DIGOUT_NID 0x06 #define ALC883_DIGIN_NID 0x0a -#define ALC1200_DIGOUT_NID 0x10 - static hda_nid_t alc883_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 @@ -7127,20 +6889,8 @@ static hda_nid_t alc883_adc_nids[2] = { 0x08, 0x09, }; -static hda_nid_t alc883_adc_nids_alt[1] = { - /* ADC1 */ - 0x08, -}; - -static hda_nid_t alc883_adc_nids_rev[2] = { - /* ADC2-1 */ - 0x09, 0x08 -}; - static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 }; -static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; - /* input MUX */ /* FIXME: should be a matrix-type input source selection */ @@ -7207,6 +6957,11 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { }, }; +#define alc883_mux_enum_info alc_mux_enum_info +#define alc883_mux_enum_get alc_mux_enum_get +/* ALC883 has the ALC882-type input selection */ +#define alc883_mux_enum_put alc882_mux_enum_put + /* * 2ch mode */ @@ -7360,6 +7115,19 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7377,6 +7145,19 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7391,6 +7172,19 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7405,6 +7199,19 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7424,6 +7231,19 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7449,6 +7269,17 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7475,6 +7306,19 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7500,6 +7344,18 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7520,6 +7376,19 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7535,6 +7404,19 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7547,6 +7429,17 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7560,6 +7453,19 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7573,6 +7479,19 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7585,6 +7504,19 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7612,6 +7544,19 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, { } /* end */ }; @@ -7642,10 +7587,6 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), { @@ -7653,9 +7594,9 @@ static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, }, { } /* end */ }; @@ -8310,6 +8251,27 @@ static struct hda_verb alc883_auto_init_verbs[] = { { } }; +/* capture mixer elements */ +static struct snd_kcontrol_new alc883_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc882_mux_enum_info, + .get = alc882_mux_enum_get, + .put = alc882_mux_enum_put, + }, + { } /* end */ +}; + static struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8432,7 +8394,6 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", [ALC883_ACER] = "acer", [ALC883_ACER_ASPIRE] = "acer-aspire", - [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", @@ -8446,9 +8407,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_MITAC] = "mitac", [ALC883_CLEVO_M720] = "clevo-m720", [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", - [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", - [ALC1200_ASUS_P5Q] = "asus-p5q", [ALC883_AUTO] = "auto", }; @@ -8459,8 +8418,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), - SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", - ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), @@ -8469,7 +8426,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), - SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), @@ -8496,7 +8452,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), @@ -8508,8 +8463,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515), - SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530", - ALC888_FUJITSU_XA3530), SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), @@ -8600,8 +8553,6 @@ static struct alc_config_preset alc883_presets[] = { .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .dig_out_nid = ALC883_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, @@ -8635,26 +8586,6 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_acer_aspire_unsol_event, .init_hook = alc883_acer_aspire_automute, }, - [ALC888_ACER_ASPIRE_4930G] = { - .mixers = { alc888_base_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_4930g_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_2_capture_sources, - .unsol_event = alc888_acer_aspire_4930g_unsol_event, - .init_hook = alc888_acer_aspire_4930g_automute, - }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, @@ -8662,8 +8593,6 @@ static struct alc_config_preset alc883_presets[] = { alc883_medion_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, @@ -8706,8 +8635,6 @@ static struct alc_config_preset alc883_presets[] = { .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_lenovo_101e_capture_source, @@ -8798,30 +8725,14 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, .init_hook = alc883_2ch_fujitsu_pi2515_automute, }, - [ALC888_FUJITSU_XA3530] = { - .mixers = { alc888_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, - alc888_fujitsu_xa3530_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes), - .channel_mode = alc888_4ST_8ch_intel_modes, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_2_capture_sources, - .unsol_event = alc888_fujitsu_xa3530_unsol_event, - .init_hook = alc888_fujitsu_xa3530_automute, - }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, @@ -8845,7 +8756,6 @@ static struct alc_config_preset alc883_presets[] = { }, [ALC888_ASUS_EEE1601] = { .mixers = { alc883_asus_eee1601_mixer }, - .cap_mixer = alc883_asus_eee1601_cap_mixer, .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -8858,17 +8768,6 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_eee1601_unsol_event, .init_hook = alc883_eee1601_inithook, }, - [ALC1200_ASUS_P5Q] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .dig_out_nid = ALC1200_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, - }, }; @@ -8963,6 +8862,8 @@ static int alc883_parse_auto_config(struct hda_codec *codec) /* hack - override the init verbs */ spec->init_verbs[0] = alc883_auto_init_verbs; + spec->mixers[spec->num_mixers] = alc883_capture_mixer; + spec->num_mixers++; return 1; /* config found */ } @@ -9045,15 +8946,9 @@ static int patch_alc883(struct hda_codec *codec) spec->stream_digital_playback = &alc883_pcm_digital_playback; spec->stream_digital_capture = &alc883_pcm_digital_capture; - if (!spec->num_adc_nids) { - spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); - spec->adc_nids = alc883_adc_nids; - } - if (!spec->capsrc_nids) - spec->capsrc_nids = alc883_capsrc_nids; - spec->is_mix_capture = 1; /* matrix-style capture */ - if (!spec->cap_mixer) - set_capture_mixer(spec); + spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); + spec->adc_nids = alc883_adc_nids; + spec->capsrc_nids = alc883_capsrc_nids; spec->vmaster_nid = 0x0c; @@ -9065,7 +8960,6 @@ static int patch_alc883(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc883_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -9545,6 +9439,20 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, { } /* end */ }; @@ -10061,7 +9969,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; int ret; - ret = alc_mux_enum_put(kcontrol, ucontrol); + ret = alc882_mux_enum_put(kcontrol, ucontrol); if (!ret) return 0; /* reprogram the HP pin as mic or HP according to the input source */ @@ -10078,8 +9986,8 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, + .info = alc882_mux_enum_info, + .get = alc882_mux_enum_get, .put = alc262_ultra_mux_enum_put, }, { } /* end */ @@ -10472,10 +10380,10 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC262_DIGIN_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - add_verb(spec, alc262_volume_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -10558,8 +10466,6 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), - SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN", - ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", ALC262_TOSHIBA_RX1), SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), @@ -10718,8 +10624,7 @@ static struct alc_config_preset alc262_presets[] = { .init_hook = alc262_hippo_automute, }, [ALC262_ULTRA] = { - .mixers = { alc262_ultra_mixer }, - .cap_mixer = alc262_ultra_capture_mixer, + .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer }, .init_verbs = { alc262_ultra_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, @@ -10845,7 +10750,6 @@ static int patch_alc262(struct hda_codec *codec) spec->stream_digital_playback = &alc262_pcm_digital_playback; spec->stream_digital_capture = &alc262_pcm_digital_capture; - spec->is_mix_capture = 1; if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -10856,14 +10760,17 @@ static int patch_alc262(struct hda_codec *codec) spec->adc_nids = alc262_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); spec->capsrc_nids = alc262_capsrc_nids_alt; + spec->mixers[spec->num_mixers] = + alc262_capture_alt_mixer; + spec->num_mixers++; } else { spec->adc_nids = alc262_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); spec->capsrc_nids = alc262_capsrc_nids; + spec->mixers[spec->num_mixers] = alc262_capture_mixer; + spec->num_mixers++; } } - if (!spec->cap_mixer) - set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -10874,7 +10781,6 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc262_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -11036,22 +10942,6 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { } }; -static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), - { } -}; - static struct hda_verb alc268_acer_aspire_one_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11328,6 +11218,10 @@ static struct hda_verb alc268_volume_init_verbs[] = { { } }; +#define alc268_mux_enum_info alc_mux_enum_info +#define alc268_mux_enum_get alc_mux_enum_get +#define alc268_mux_enum_put alc_mux_enum_put + static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), @@ -11339,9 +11233,9 @@ static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, + .info = alc268_mux_enum_info, + .get = alc268_mux_enum_get, + .put = alc268_mux_enum_put, }, { } /* end */ }; @@ -11359,9 +11253,9 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, + .info = alc268_mux_enum_info, + .get = alc268_mux_enum_get, + .put = alc268_mux_enum_put, }, { } /* end */ }; @@ -11380,15 +11274,6 @@ static struct hda_input_mux alc268_acer_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static struct hda_input_mux alc268_acer_dmic_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, { "Internal Mic", 0x6 }, { "Line", 0x2 }, }, @@ -11627,13 +11512,13 @@ static int alc268_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; if (spec->autocfg.speaker_pins[0] != 0x1d) - add_mixer(spec, alc268_beep_mixer); + spec->mixers[spec->num_mixers++] = alc268_beep_mixer; - add_verb(spec, alc268_volume_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -11669,7 +11554,6 @@ static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC268_3ST] = "3stack", [ALC268_TOSHIBA] = "toshiba", [ALC268_ACER] = "acer", - [ALC268_ACER_DMIC] = "acer-dmic", [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", [ALC268_DELL] = "dell", [ALC268_ZEPTO] = "zepto", @@ -11765,23 +11649,6 @@ static struct alc_config_preset alc268_presets[] = { .unsol_event = alc268_acer_unsol_event, .init_hook = alc268_acer_init_hook, }, - [ALC268_ACER_DMIC] = { - .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, - alc268_beep_mixer }, - .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, - alc268_acer_verbs }, - .num_dacs = ARRAY_SIZE(alc268_dac_nids), - .dac_nids = alc268_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), - .adc_nids = alc268_adc_nids_alt, - .capsrc_nids = alc268_capsrc_nids, - .hp_nid = 0x02, - .num_channel_mode = ARRAY_SIZE(alc268_modes), - .channel_mode = alc268_modes, - .input_mux = &alc268_acer_dmic_capture_source, - .unsol_event = alc268_acer_unsol_event, - .init_hook = alc268_acer_init_hook, - }, [ALC268_ACER_ASPIRE_ONE] = { .mixers = { alc268_acer_aspire_one_mixer, alc268_capture_alt_mixer }, @@ -11920,11 +11787,15 @@ static int patch_alc268(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc268_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); - add_mixer(spec, alc268_capture_alt_mixer); + spec->mixers[spec->num_mixers] = + alc268_capture_alt_mixer; + spec->num_mixers++; } else { spec->adc_nids = alc268_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); - add_mixer(spec, alc268_capture_mixer); + spec->mixers[spec->num_mixers] = + alc268_capture_mixer; + spec->num_mixers++; } spec->capsrc_nids = alc268_capsrc_nids; /* set default input source */ @@ -11940,8 +11811,6 @@ static int patch_alc268(struct hda_codec *codec) if (board_config == ALC268_AUTO) spec->init_hook = alc268_auto_init; - codec->proc_widget_hook = print_realtek_coef; - return 0; } @@ -12024,31 +11893,6 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { } }; -static struct snd_kcontrol_new alc269_lifebook_mixer[] = { - /* output mixer control */ - HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = alc268_acer_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT), - { } -}; - /* bind volumes of both NID 0x0c and 0x0d */ static struct hda_bind_ctls alc269_epc_bind_vol = { .ops = &snd_hda_bind_vol, @@ -12067,18 +11911,28 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = { }; /* capture mixer elements */ -static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { +static struct snd_kcontrol_new alc269_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, { } /* end */ }; -/* FSC amilo */ -static struct snd_kcontrol_new alc269_fujitsu_mixer[] = { - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol), +/* capture mixer elements */ +static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), { } /* end */ }; @@ -12099,20 +11953,6 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = { { } }; -static struct hda_verb alc269_lifebook_verbs[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - { } -}; - /* toggle speaker-output according to the hp-jack state */ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) { @@ -12138,37 +11978,6 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x480); } -/* toggle speaker-output according to the hp-jacks state */ -static void alc269_lifebook_speaker_automute(struct hda_codec *codec) -{ - unsigned int present; - unsigned char bits; - - /* Check laptop headphone socket */ - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - - /* Check port replicator headphone socket */ - present |= snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - - bits = present ? AMP_IN_MUTE(0) : 0; - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, - AMP_IN_MUTE(0), bits); - snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, - AMP_IN_MUTE(0), bits); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); -} - static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -12179,29 +11988,6 @@ static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1); } -static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) -{ - unsigned int present_laptop; - unsigned int present_dock; - - present_laptop = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - - present_dock = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - - /* Laptop mic port overrides dock mic port, design decision */ - if (present_dock) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x3); - if (present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x0); - if (!present_dock && !present_laptop) - snd_hda_codec_write(codec, 0x23, 0, - AC_VERB_SET_CONNECT_SEL, 0x1); -} - static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -12211,27 +11997,12 @@ static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, alc269_quanta_fl1_mic_automute(codec); } -static void alc269_lifebook_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) == ALC880_HP_EVENT) - alc269_lifebook_speaker_automute(codec); - if ((res >> 26) == ALC880_MIC_EVENT) - alc269_lifebook_mic_autoswitch(codec); -} - static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) { alc269_quanta_fl1_speaker_automute(codec); alc269_quanta_fl1_mic_automute(codec); } -static void alc269_lifebook_init_hook(struct hda_codec *codec) -{ - alc269_lifebook_speaker_automute(codec); - alc269_lifebook_mic_autoswitch(codec); -} - static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, @@ -12532,17 +12303,17 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; /* create a beep mixer control if the pin 0x1d isn't assigned */ for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) if (spec->autocfg.input_pins[i] == 0x1d) break; if (i >= ARRAY_SIZE(spec->autocfg.input_pins)) - add_mixer(spec, alc269_beep_mixer); + spec->mixers[spec->num_mixers++] = alc269_beep_mixer; - add_verb(spec, alc269_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; /* set default input source */ @@ -12554,8 +12325,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - if (!spec->cap_mixer) - set_capture_mixer(spec); + spec->mixers[spec->num_mixers] = alc269_capture_mixer; + spec->num_mixers++; store_pin_configs(codec); return 1; @@ -12584,9 +12355,7 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_BASIC] = "basic", [ALC269_QUANTA_FL1] = "quanta", [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", - [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", - [ALC269_FUJITSU] = "fujitsu", - [ALC269_LIFEBOOK] = "lifebook" + [ALC269_ASUS_EEEPC_P901] = "eeepc-p901" }; static struct snd_pci_quirk alc269_cfg_tbl[] = { @@ -12597,14 +12366,12 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { ALC269_ASUS_EEEPC_P901), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", ALC269_ASUS_EEEPC_P901), - SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), - SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), {} }; static struct alc_config_preset alc269_presets[] = { [ALC269_BASIC] = { - .mixers = { alc269_base_mixer }, + .mixers = { alc269_base_mixer, alc269_capture_mixer }, .init_verbs = { alc269_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), .dac_nids = alc269_dac_nids, @@ -12626,8 +12393,7 @@ static struct alc_config_preset alc269_presets[] = { .init_hook = alc269_quanta_fl1_init_hook, }, [ALC269_ASUS_EEEPC_P703] = { - .mixers = { alc269_eeepc_mixer }, - .cap_mixer = alc269_epc_capture_mixer, + .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer }, .init_verbs = { alc269_init_verbs, alc269_eeepc_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), @@ -12640,8 +12406,7 @@ static struct alc_config_preset alc269_presets[] = { .init_hook = alc269_eeepc_amic_inithook, }, [ALC269_ASUS_EEEPC_P901] = { - .mixers = { alc269_eeepc_mixer }, - .cap_mixer = alc269_epc_capture_mixer, + .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer}, .init_verbs = { alc269_init_verbs, alc269_eeepc_dmic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), @@ -12653,32 +12418,6 @@ static struct alc_config_preset alc269_presets[] = { .unsol_event = alc269_eeepc_dmic_unsol_event, .init_hook = alc269_eeepc_dmic_inithook, }, - [ALC269_FUJITSU] = { - .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer }, - .cap_mixer = alc269_epc_capture_mixer, - .init_verbs = { alc269_init_verbs, - alc269_eeepc_dmic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_eeepc_dmic_capture_source, - .unsol_event = alc269_eeepc_dmic_unsol_event, - .init_hook = alc269_eeepc_dmic_inithook, - }, - [ALC269_LIFEBOOK] = { - .mixers = { alc269_lifebook_mixer }, - .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, - .num_dacs = ARRAY_SIZE(alc269_dac_nids), - .dac_nids = alc269_dac_nids, - .hp_nid = 0x03, - .num_channel_mode = ARRAY_SIZE(alc269_modes), - .channel_mode = alc269_modes, - .input_mux = &alc269_capture_source, - .unsol_event = alc269_lifebook_unsol_event, - .init_hook = alc269_lifebook_init_hook, - }, }; static int patch_alc269(struct hda_codec *codec) @@ -12733,8 +12472,6 @@ static int patch_alc269(struct hda_codec *codec) spec->adc_nids = alc269_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; - if (!spec->cap_mixer) - set_capture_mixer(spec); codec->patch_ops = alc_patch_ops; if (board_config == ALC269_AUTO) @@ -12743,7 +12480,6 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc269_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -12876,6 +12612,17 @@ static struct snd_kcontrol_new alc861_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), + /* Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, { } /* end */ }; @@ -12899,6 +12646,17 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), + /* Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -12916,6 +12674,18 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), + /*Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ }; @@ -12939,6 +12709,17 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), + /* Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -12970,6 +12751,17 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), + /* Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -13501,6 +13293,25 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, return 0; } +static struct snd_kcontrol_new alc861_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, int dac_idx) @@ -13591,17 +13402,18 @@ static int alc861_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - add_verb(spec, alc861_auto_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - set_capture_mixer(spec); + spec->mixers[spec->num_mixers] = alc861_capture_mixer; + spec->num_mixers++; store_pin_configs(codec); return 1; @@ -13832,7 +13644,6 @@ static int patch_alc861(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -13898,6 +13709,11 @@ static struct hda_input_mux alc861vd_hp_capture_source = { }, }; +#define alc861vd_mux_enum_info alc_mux_enum_info +#define alc861vd_mux_enum_get alc_mux_enum_get +/* ALC861VD has the ALC882-type input selection (but has only one ADC) */ +#define alc861vd_mux_enum_put alc882_mux_enum_put + /* * 2ch mode */ @@ -13943,6 +13759,25 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc861vd_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc861vd_mux_enum_info, + .get = alc861vd_mux_enum_get, + .put = alc861vd_mux_enum_put, + }, + { } /* end */ +}; + /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -14334,7 +14169,6 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", [ALC660VD_3ST_DIG] = "3stack-660-digout", - [ALC660VD_ASUS_V1S] = "asus-v1s", [ALC861VD_3ST] = "3stack", [ALC861VD_3ST_DIG] = "3stack-digout", [ALC861VD_6ST_DIG] = "6stack-digout", @@ -14349,7 +14183,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), - SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), + SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), @@ -14456,21 +14290,6 @@ static struct alc_config_preset alc861vd_presets[] = { .unsol_event = alc861vd_dallas_unsol_event, .init_hook = alc861vd_dallas_automute, }, - [ALC660VD_ASUS_V1S] = { - .mixers = { alc861vd_lenovo_mixer }, - .init_verbs = { alc861vd_volume_init_verbs, - alc861vd_3stack_init_verbs, - alc861vd_eapd_verbs, - alc861vd_lenovo_unsol_verbs }, - .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), - .dac_nids = alc660vd_dac_nids, - .dig_out_nid = ALC861VD_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), - .channel_mode = alc861vd_3stack_2ch_modes, - .input_mux = &alc861vd_capture_source, - .unsol_event = alc861vd_lenovo_unsol_event, - .init_hook = alc861vd_lenovo_automute, - }, }; /* @@ -14695,10 +14514,11 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; - add_verb(spec, alc861vd_volume_init_verbs); + spec->init_verbs[spec->num_init_verbs++] + = alc861vd_volume_init_verbs; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -14765,7 +14585,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->stream_name_analog = "ALC660-VD Analog"; spec->stream_name_digital = "ALC660-VD Digital"; /* always turn on EAPD */ - add_verb(spec, alc660vd_eapd_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs; } else { spec->stream_name_analog = "ALC861VD Analog"; spec->stream_name_digital = "ALC861VD Digital"; @@ -14780,9 +14600,9 @@ static int patch_alc861vd(struct hda_codec *codec) spec->adc_nids = alc861vd_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; - spec->is_mix_capture = 1; - set_capture_mixer(spec); + spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; + spec->num_mixers++; spec->vmaster_nid = 0x02; @@ -14794,7 +14614,6 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861vd_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -14870,6 +14689,10 @@ static struct hda_input_mux alc663_m51va_capture_source = { }, }; +#define alc662_mux_enum_info alc_mux_enum_info +#define alc662_mux_enum_get alc_mux_enum_get +#define alc662_mux_enum_put alc882_mux_enum_put + /* * 2ch mode */ @@ -15455,6 +15278,25 @@ static struct hda_verb alc662_ecs_init_verbs[] = { {} }; +/* capture mixer elements */ +static struct snd_kcontrol_new alc662_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc662_mux_enum_info, + .get = alc662_mux_enum_get, + .put = alc662_mux_enum_put, + }, + { } /* end */ +}; + static struct snd_kcontrol_new alc662_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), @@ -16026,7 +15868,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { static struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer }, + .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16037,7 +15879,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16049,7 +15892,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16059,7 +15903,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer }, + .mixers = { alc662_base_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16070,7 +15915,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer }, + .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16081,7 +15926,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_lenovo_101e_all_automute, }, [ALC662_ASUS_EEEPC_P701] = { - .mixers = { alc662_eeepc_p701_mixer }, + .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs, alc662_eeepc_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16093,7 +15938,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_inithook, }, [ALC662_ASUS_EEEPC_EP20] = { - .mixers = { alc662_eeepc_ep20_mixer, + .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs, alc662_eeepc_ep20_sue_init_verbs }, @@ -16106,7 +15951,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { - .mixers = { alc662_ecs_mixer }, + .mixers = { alc662_ecs_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs, alc662_ecs_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16118,7 +15963,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_inithook, }, [ALC663_ASUS_M51VA] = { - .mixers = { alc663_m51va_mixer }, + .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16130,7 +15975,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G71V] = { - .mixers = { alc663_g71v_mixer }, + .mixers = { alc663_g71v_mixer, alc662_capture_mixer}, .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16142,7 +15987,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_g71v_inithook, }, [ALC663_ASUS_H13] = { - .mixers = { alc663_m51va_mixer }, + .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16153,7 +15998,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G50V] = { - .mixers = { alc663_g50v_mixer }, + .mixers = { alc663_g50v_mixer, alc662_capture_mixer}, .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -16165,8 +16010,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_g50v_inithook, }, [ALC663_ASUS_MODE1] = { - .mixers = { alc663_m51va_mixer }, - .cap_mixer = alc662_auto_capture_mixer, + .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer }, .init_verbs = { alc662_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16180,8 +16024,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode1_inithook, }, [ALC662_ASUS_MODE2] = { - .mixers = { alc662_1bjd_mixer }, - .cap_mixer = alc662_auto_capture_mixer, + .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer }, .init_verbs = { alc662_init_verbs, alc662_1bjd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16194,8 +16037,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_mode2_inithook, }, [ALC663_ASUS_MODE3] = { - .mixers = { alc663_two_hp_m1_mixer }, - .cap_mixer = alc662_auto_capture_mixer, + .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer }, .init_verbs = { alc662_init_verbs, alc663_two_hp_amic_m1_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16209,8 +16051,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode3_inithook, }, [ALC663_ASUS_MODE4] = { - .mixers = { alc663_asus_21jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, + .mixers = { alc663_asus_21jd_clfe_mixer, + alc662_auto_capture_mixer}, .init_verbs = { alc662_init_verbs, alc663_21jd_amic_init_verbs}, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16224,8 +16066,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode4_inithook, }, [ALC663_ASUS_MODE5] = { - .mixers = { alc663_asus_15jd_clfe_mixer }, - .cap_mixer = alc662_auto_capture_mixer, + .mixers = { alc663_asus_15jd_clfe_mixer, + alc662_auto_capture_mixer }, .init_verbs = { alc662_init_verbs, alc663_15jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16239,8 +16081,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode5_inithook, }, [ALC663_ASUS_MODE6] = { - .mixers = { alc663_two_hp_m2_mixer }, - .cap_mixer = alc662_auto_capture_mixer, + .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer }, .init_verbs = { alc662_init_verbs, alc663_two_hp_amic_m2_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16501,20 +16342,24 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; - add_verb(spec, alc662_auto_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs; if (codec->vendor_id == 0x10ec0663) - add_verb(spec, alc663_auto_init_verbs); + spec->init_verbs[spec->num_init_verbs++] = + alc663_auto_init_verbs; err = alc_auto_add_mic_boost(codec); if (err < 0) return err; + spec->mixers[spec->num_mixers] = alc662_capture_mixer; + spec->num_mixers++; + store_pin_configs(codec); return 1; } @@ -16590,10 +16435,6 @@ static int patch_alc662(struct hda_codec *codec) spec->adc_nids = alc662_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); spec->capsrc_nids = alc662_capsrc_nids; - spec->is_mix_capture = 1; - - if (!spec->cap_mixer) - set_capture_mixer(spec); spec->vmaster_nid = 0x02; @@ -16604,7 +16445,6 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc662_loopbacks; #endif - codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -16612,7 +16452,7 @@ static int patch_alc662(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_realtek[] = { +struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, @@ -16644,26 +16484,3 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:10ec*"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Realtek HD-audio codec"); - -static struct hda_codec_preset_list realtek_list = { - .preset = snd_hda_preset_realtek, - .owner = THIS_MODULE, -}; - -static int __init patch_realtek_init(void) -{ - return snd_hda_add_codec_preset(&realtek_list); -} - -static void __exit patch_realtek_exit(void) -{ - snd_hda_delete_codec_preset(&realtek_list); -} - -module_init(patch_realtek_init) -module_exit(patch_realtek_exit) diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 43b436c5d01b..9332b63e406c 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -28,6 +28,7 @@ #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" /* si3054 verbs */ #define SI3054_VERB_READ_NODE 0x900 @@ -282,7 +283,7 @@ static int patch_si3054(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_si3054[] = { +struct hda_codec_preset snd_hda_preset_si3054[] = { { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, @@ -300,35 +301,3 @@ static struct hda_codec_preset snd_hda_preset_si3054[] = { {} }; -MODULE_ALIAS("snd-hda-codec-id:163c3055"); -MODULE_ALIAS("snd-hda-codec-id:163c3155"); -MODULE_ALIAS("snd-hda-codec-id:11c13026"); -MODULE_ALIAS("snd-hda-codec-id:11c13055"); -MODULE_ALIAS("snd-hda-codec-id:11c13155"); -MODULE_ALIAS("snd-hda-codec-id:10573055"); -MODULE_ALIAS("snd-hda-codec-id:10573057"); -MODULE_ALIAS("snd-hda-codec-id:10573155"); -MODULE_ALIAS("snd-hda-codec-id:11063288"); -MODULE_ALIAS("snd-hda-codec-id:15433155"); -MODULE_ALIAS("snd-hda-codec-id:18540018"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Si3054 HD-audio modem codec"); - -static struct hda_codec_preset_list si3054_list = { - .preset = snd_hda_preset_si3054, - .owner = THIS_MODULE, -}; - -static int __init patch_si3054_init(void) -{ - return snd_hda_add_codec_preset(&si3054_list); -} - -static void __exit patch_si3054_exit(void) -{ - snd_hda_delete_codec_preset(&si3054_list); -} - -module_init(patch_si3054_init) -module_exit(patch_si3054_exit) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4c851fd55565..5dd3e89f620a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -30,17 +30,17 @@ #include <linux/pci.h> #include <sound/core.h> #include <sound/asoundef.h> -#include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" #include "hda_beep.h" -enum { - STAC_VREF_EVENT = 1, - STAC_INSERT_EVENT, - STAC_PWR_EVENT, - STAC_HP_EVENT, -}; +#define NUM_CONTROL_ALLOC 32 + +#define STAC_VREF_EVENT 0x00 +#define STAC_INSERT_EVENT 0x10 +#define STAC_PWR_EVENT 0x20 +#define STAC_HP_EVENT 0x30 enum { STAC_REF, @@ -135,19 +135,6 @@ enum { STAC_927X_MODELS }; -struct sigmatel_event { - hda_nid_t nid; - unsigned char type; - unsigned char tag; - int data; -}; - -struct sigmatel_jack { - hda_nid_t nid; - int type; - struct snd_jack *jack; -}; - struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -181,12 +168,6 @@ struct sigmatel_spec { hda_nid_t *pwr_nids; hda_nid_t *dac_list; - /* jack detection */ - struct snd_array jacks; - - /* events */ - struct snd_array events; - /* playback */ struct hda_input_mux *mono_mux; struct hda_input_mux *amp_mux; @@ -216,6 +197,7 @@ struct sigmatel_spec { hda_nid_t *pin_nids; unsigned int num_pins; unsigned int *pin_configs; + unsigned int *bios_pin_configs; /* codec specific stuff */ struct hda_verb *init; @@ -243,7 +225,8 @@ struct sigmatel_spec { /* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; - struct snd_array kctls; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_dimux; struct hda_input_mux private_imux; struct hda_input_mux private_smux; @@ -589,12 +572,12 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, else nid = codec->slave_dig_outs[smux_idx - 1]; if (spec->cur_smux[smux_idx] == smux->num_items - 1) - val = HDA_AMP_MUTE; + val = AMP_OUT_MUTE; else - val = 0; + val = AMP_OUT_UNMUTE; /* un/mute SPDIF out */ - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, val); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); } return 0; } @@ -1253,14 +1236,9 @@ static const char *slave_sws[] = { NULL }; -static void stac92xx_free_kctls(struct hda_codec *codec); -static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type); - static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; int err; int i; @@ -1275,7 +1253,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) } if (spec->num_dmuxes > 0) { stac_dmux_mixer.count = spec->num_dmuxes; - err = snd_hda_ctl_add(codec, + err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&stac_dmux_mixer, codec)); if (err < 0) return err; @@ -1330,37 +1308,6 @@ static int stac92xx_build_controls(struct hda_codec *codec) return err; } - stac92xx_free_kctls(codec); /* no longer needed */ - - /* create jack input elements */ - if (spec->hp_detect) { - for (i = 0; i < cfg->hp_outs; i++) { - int type = SND_JACK_HEADPHONE; - nid = cfg->hp_pins[i]; - /* jack detection */ - if (cfg->hp_outs == i) - type |= SND_JACK_LINEOUT; - err = stac92xx_add_jack(codec, nid, type); - if (err < 0) - return err; - } - } - for (i = 0; i < cfg->line_outs; i++) { - err = stac92xx_add_jack(codec, cfg->line_out_pins[i], - SND_JACK_LINEOUT); - if (err < 0) - return err; - } - for (i = 0; i < AUTO_PIN_LAST; i++) { - nid = cfg->input_pins[i]; - if (nid) { - err = stac92xx_add_jack(codec, nid, - SND_JACK_MICROPHONE); - if (err < 0) - return err; - } - } - return 0; } @@ -2246,11 +2193,12 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) int i; struct sigmatel_spec *spec = codec->spec; - kfree(spec->pin_configs); - spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs), - GFP_KERNEL); - if (!spec->pin_configs) - return -ENOMEM; + if (! spec->bios_pin_configs) { + spec->bios_pin_configs = kcalloc(spec->num_pins, + sizeof(*spec->bios_pin_configs), GFP_KERNEL); + if (! spec->bios_pin_configs) + return -ENOMEM; + } for (i = 0; i < spec->num_pins; i++) { hda_nid_t nid = spec->pin_nids[i]; @@ -2260,7 +2208,7 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) AC_VERB_GET_CONFIG_DEFAULT, 0x00); snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", nid, pin_cfg); - spec->pin_configs[i] = pin_cfg; + spec->bios_pin_configs[i] = pin_cfg; } return 0; @@ -2302,39 +2250,6 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) spec->pin_configs[i]); } -static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins) -{ - struct sigmatel_spec *spec = codec->spec; - - if (!pins) - return stac92xx_save_bios_config_regs(codec); - - kfree(spec->pin_configs); - spec->pin_configs = kmemdup(pins, - spec->num_pins * sizeof(*pins), - GFP_KERNEL); - if (!spec->pin_configs) - return -ENOMEM; - - stac92xx_set_config_regs(codec); - return 0; -} - -static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid, - unsigned int cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_pins; i++) { - if (spec->pin_nids[i] == nid) { - spec->pin_configs[i] = cfg; - stac92xx_set_config_reg(codec, nid, cfg); - break; - } - } -} - /* * Analog playback callbacks */ @@ -2412,7 +2327,7 @@ static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, if (spec->powerdown_adcs) { msleep(40); - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); } snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); @@ -2428,7 +2343,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, snd_hda_codec_cleanup_stream(codec, nid); if (spec->powerdown_adcs) - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); return 0; } @@ -2560,9 +2475,6 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, return 0; } -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, - unsigned char type); - static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2575,7 +2487,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, /* check to be sure that the ports are upto date with * switch changes */ - stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); return 1; } @@ -2615,7 +2527,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ * appropriately according to the pin direction */ if (spec->hp_detect) - stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); return 1; } @@ -2710,16 +2622,28 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return -ENOMEM; + if (spec->num_kctl_used >= spec->num_kctl_alloc) { + int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; + + knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ + if (! knew) + return -ENOMEM; + if (spec->kctl_alloc) { + memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); + kfree(spec->kctl_alloc); + } + spec->kctl_alloc = knew; + spec->num_kctl_alloc = num; + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; *knew = *ktemp; knew->index = idx; knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; knew->private_value = val; + spec->num_kctl_used++; return 0; } @@ -3596,8 +3520,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if (dig_in && spec->autocfg.dig_in_pin) spec->dig_in_nid = dig_in; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; @@ -3704,8 +3628,8 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = 0x04; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; @@ -3749,101 +3673,13 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ } -static int stac92xx_add_jack(struct hda_codec *codec, - hda_nid_t nid, int type) -{ -#ifdef CONFIG_SND_JACK - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_jack *jack; - int def_conf = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - int connectivity = get_defcfg_connect(def_conf); - char name[32]; - - if (connectivity && connectivity != AC_JACK_PORT_FIXED) - return 0; - - snd_array_init(&spec->jacks, sizeof(*jack), 32); - jack = snd_array_new(&spec->jacks); - if (!jack) - return -ENOMEM; - jack->nid = nid; - jack->type = type; - - sprintf(name, "%s at %s %s Jack", - snd_hda_get_jack_type(def_conf), - snd_hda_get_jack_connectivity(def_conf), - snd_hda_get_jack_location(def_conf)); - - return snd_jack_new(codec->bus->card, name, type, &jack->jack); -#else - return 0; -#endif -} - -static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, - unsigned char type, int data) -{ - struct sigmatel_event *event; - - snd_array_init(&spec->events, sizeof(*event), 32); - event = snd_array_new(&spec->events); - if (!event) - return -ENOMEM; - event->nid = nid; - event->type = type; - event->tag = spec->events.used; - event->data = data; - - return event->tag; -} - -static struct sigmatel_event *stac_get_event(struct hda_codec *codec, - hda_nid_t nid, unsigned char type) -{ - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_event *event = spec->events.list; - int i; - - for (i = 0; i < spec->events.used; i++, event++) { - if (event->nid == nid && event->type == type) - return event; - } - return NULL; -} - -static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec, - unsigned char tag) -{ - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_event *event = spec->events.list; - int i; - - for (i = 0; i < spec->events.used; i++, event++) { - if (event->tag == tag) - return event; - } - return NULL; -} - static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int type) + unsigned int event) { - struct sigmatel_event *event; - int tag; - - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) - return; - event = stac_get_event(codec, nid, type); - if (event) - tag = event->tag; - else - tag = stac_add_event(codec->spec, nid, type, 0); - if (tag < 0) - return; - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | tag); + if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | event)); } static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) @@ -3865,7 +3701,7 @@ static void stac92xx_power_down(struct hda_codec *codec) for (dac = spec->dac_list; *dac; dac++) if (!is_in_dac_nids(spec, *dac) && spec->multiout.hp_nid != *dac) - snd_hda_codec_write(codec, *dac, 0, + snd_hda_codec_write_cache(codec, *dac, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } @@ -3884,7 +3720,7 @@ static int stac92xx_init(struct hda_codec *codec) /* power down adcs initially */ if (spec->powerdown_adcs) for (i = 0; i < spec->num_adcs; i++) - snd_hda_codec_write(codec, + snd_hda_codec_write_cache(codec, spec->adc_nids[i], 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); @@ -3900,51 +3736,37 @@ static int stac92xx_init(struct hda_codec *codec) /* set up pins */ if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - enable_pin_detect(codec, nid, STAC_HP_EVENT); - } + for (i = 0; i < cfg->hp_outs; i++) + enable_pin_detect(codec, cfg->hp_pins[i], + STAC_HP_EVENT); /* force to enable the first line-out; the others are set up * in unsol_event */ stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], - AC_PINCTL_OUT_EN); + AC_PINCTL_OUT_EN); + stac92xx_auto_init_hp_out(codec); /* fake event to set up pins */ - stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], - STAC_HP_EVENT); + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); - for (i = 0; i < cfg->hp_outs; i++) - stac_toggle_power_map(codec, cfg->hp_pins[i], 1); } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { - unsigned int pinctl, conf; + unsigned int pinctl; if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { /* for mic pins, force to initialize */ pinctl = stac92xx_get_vref(codec, nid); - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, pinctl); } else { pinctl = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); /* if PINCTL already set then skip */ - if (!(pinctl & AC_PINCTL_IN_EN)) { - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, - pinctl); - } - } - conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { - enable_pin_detect(codec, nid, - STAC_INSERT_EVENT); - stac_issue_unsol_event(codec, nid, - STAC_INSERT_EVENT); + if (pinctl & AC_PINCTL_IN_EN) + continue; } + pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, pinctl); } } for (i = 0; i < spec->num_dmics; i++) @@ -3959,6 +3781,7 @@ static int stac92xx_init(struct hda_codec *codec) for (i = 0; i < spec->num_pwrs; i++) { hda_nid_t nid = spec->pwr_nids[i]; int pinctl, def_conf; + int event = STAC_PWR_EVENT; if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) continue; /* already has an unsol event */ @@ -3981,54 +3804,30 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) { - enable_pin_detect(codec, nid, STAC_PWR_EVENT); - stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); - } + enable_pin_detect(codec, spec->pwr_nids[i], event | i); + codec->patch_ops.unsol_event(codec, (event | i) << 26); } if (spec->dac_list) stac92xx_power_down(codec); return 0; } -static void stac92xx_free_jacks(struct hda_codec *codec) -{ -#ifdef CONFIG_SND_JACK - /* free jack instances manually when clearing/reconfiguring */ - struct sigmatel_spec *spec = codec->spec; - if (!codec->bus->shutdown && spec->jacks.list) { - struct sigmatel_jack *jacks = spec->jacks.list; - int i; - for (i = 0; i < spec->jacks.used; i++) - snd_device_free(codec->bus->card, &jacks[i].jack); - } - snd_array_free(&spec->jacks); -#endif -} - -static void stac92xx_free_kctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - static void stac92xx_free(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; + int i; if (! spec) return; - kfree(spec->pin_configs); - stac92xx_free_jacks(codec); - snd_array_free(&spec->events); + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } + + if (spec->bios_pin_configs) + kfree(spec->bios_pin_configs); kfree(spec); snd_hda_detach_beep_device(codec); @@ -4075,13 +3874,20 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, pin_ctl & ~flag); } -static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) +static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) { if (!nid) return 0; if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) - & (1 << 31)) - return 1; + & (1 << 31)) { + unsigned int pinctl; + pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pinctl & AC_PINCTL_IN_EN) + return 0; /* mic- or line-input */ + else + return 1; /* HP-output */ + } return 0; } @@ -4105,7 +3911,7 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i) return 0; } -static void stac92xx_hp_detect(struct hda_codec *codec) +static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -4121,14 +3927,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec) break; if (no_hp_sensing(spec, i)) continue; - presence = get_pin_presence(codec, cfg->hp_pins[i]); - if (presence) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - presence = 0; /* mic- or line-input */ - } + presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); } if (presence) { @@ -4205,145 +4004,50 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) { - stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); -} - -static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_jack *jacks = spec->jacks.list; - - if (jacks) { - int i; - for (i = 0; i < spec->jacks.used; i++) { - if (jacks->nid == nid) { - unsigned int pin_ctl = - snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, - 0x00); - int type = jacks->type; - if (type == (SND_JACK_LINEOUT - | SND_JACK_HEADPHONE)) - type = (pin_ctl & AC_PINCTL_HP_EN) - ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT; - snd_jack_report(jacks->jack, - get_pin_presence(codec, nid) - ? type : 0); - } - jacks++; - } - } -} - -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, - unsigned char type) -{ - struct sigmatel_event *event = stac_get_event(codec, nid, type); - if (!event) - return; - codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); + stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid)); } static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; - struct sigmatel_event *event; - int tag, data; + int idx = res >> 26 & 0x0f; - tag = (res >> 26) & 0x7f; - event = stac_get_event_from_tag(codec, tag); - if (!event) - return; - - switch (event->type) { + switch ((res >> 26) & 0x70) { case STAC_HP_EVENT: - stac92xx_hp_detect(codec); + stac92xx_hp_detect(codec, res); /* fallthru */ - case STAC_INSERT_EVENT: case STAC_PWR_EVENT: if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, event->nid); - stac92xx_report_jack(codec, event->nid); + stac92xx_pin_sense(codec, idx); break; - case STAC_VREF_EVENT: - data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); + case STAC_VREF_EVENT: { + int data = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); /* toggle VREF state based on GPIOx status */ snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, - !!(data & (1 << event->data))); + !!(data & (1 << idx))); break; + } } } -#ifdef CONFIG_PROC_FS -static void stac92hd_proc_hook(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - if (nid == codec->afg) - snd_iprintf(buffer, "Power-Map: 0x%02x\n", - snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0)); -} - -static void analog_loop_proc_hook(struct snd_info_buffer *buffer, - struct hda_codec *codec, - unsigned int verb) -{ - snd_iprintf(buffer, "Analog Loopback: 0x%02x\n", - snd_hda_codec_read(codec, codec->afg, 0, verb, 0)); -} - -/* stac92hd71bxx, stac92hd73xx */ -static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - stac92hd_proc_hook(buffer, codec, nid); - if (nid == codec->afg) - analog_loop_proc_hook(buffer, codec, 0xfa0); -} - -static void stac9205_proc_hook(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - if (nid == codec->afg) - analog_loop_proc_hook(buffer, codec, 0xfe0); -} - -static void stac927x_proc_hook(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - if (nid == codec->afg) - analog_loop_proc_hook(buffer, codec, 0xfeb); -} -#else -#define stac92hd_proc_hook NULL -#define stac92hd7x_proc_hook NULL -#define stac9205_proc_hook NULL -#define stac927x_proc_hook NULL -#endif - #ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; stac92xx_set_config_regs(codec); - stac92xx_init(codec); + snd_hda_sequence_write(codec, spec->init); + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - /* fake event to set up pins again to override cached values */ + /* power down inactive DACs */ + if (spec->dac_list) + stac92xx_power_down(codec); + /* invoke unsolicited event to reset the HP state */ if (spec->hp_detect) - stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], - STAC_HP_EVENT); - return 0; -} - -static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) -{ - struct sigmatel_spec *spec = codec->spec; - if (spec->eapd_mask) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); return 0; } #endif @@ -4355,7 +4059,6 @@ static struct hda_codec_ops stac92xx_patch_ops = { .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, #ifdef SND_HDA_NEEDS_RESUME - .suspend = stac92xx_suspend, .resume = stac92xx_resume, #endif }; @@ -4378,12 +4081,14 @@ static int patch_stac9200(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac9200_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else { + spec->pin_configs = stac9200_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } spec->multiout.max_channels = 2; @@ -4439,12 +4144,14 @@ static int patch_stac925x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac925x_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else if (stac925x_brd_tbl[spec->board_config] != NULL){ + spec->pin_configs = stac925x_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } spec->multiout.max_channels = 2; @@ -4526,12 +4233,14 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD73XX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac92hd73xx_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else { + spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, @@ -4644,8 +4353,6 @@ again: codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac92hd7x_proc_hook; - return 0; } @@ -4706,12 +4413,14 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD83XXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac92hd83xxx_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else { + spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } err = stac92xx_parse_auto_config(codec, 0x1d, 0); @@ -4732,11 +4441,57 @@ again: codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac92hd_proc_hook; - return 0; } +#ifdef SND_HDA_NEEDS_RESUME +static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_POWER_STATE, pwr); + + msleep(1); + for (i = 0; i < spec->num_adcs; i++) { + snd_hda_codec_write_cache(codec, + spec->adc_nids[i], 0, + AC_VERB_SET_POWER_STATE, pwr); + } +}; + +static int stac92hd71xx_resume(struct hda_codec *codec) +{ + stac92hd71xx_set_power_state(codec, AC_PWRST_D0); + return stac92xx_resume(codec); +} + +static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct sigmatel_spec *spec = codec->spec; + + stac92hd71xx_set_power_state(codec, AC_PWRST_D3); + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); + return 0; +}; + +#endif + +static struct hda_codec_ops stac92hd71bxx_patch_ops = { + .build_controls = stac92xx_build_controls, + .build_pcms = stac92xx_build_pcms, + .init = stac92xx_init, + .free = stac92xx_free, + .unsol_event = stac92xx_unsol_event, +#ifdef SND_HDA_NEEDS_RESUME + .resume = stac92hd71xx_resume, + .suspend = stac92hd71xx_suspend, +#endif +}; + static struct hda_input_mux stac92hd71bxx_dmux = { .num_items = 4, .items = { @@ -4772,12 +4527,14 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD71BXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac92hd71bxx_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else { + spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } if (spec->board_config > STAC_92HD71BXX_REF) { @@ -4800,21 +4557,21 @@ again: switch (spec->board_config) { case STAC_HP_M4: /* Enable VREF power saving on GPIO1 detect */ - err = stac_add_event(spec, codec->afg, - STAC_VREF_EVENT, 0x02); - if (err < 0) - return err; snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | err); + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | STAC_VREF_EVENT | 0x01)); spec->gpio_mask |= 0x02; break; } if ((codec->revision_id & 0xf) == 0 || - (codec->revision_id & 0xf) == 1) + (codec->revision_id & 0xf) == 1) { +#ifdef SND_HDA_NEEDS_RESUME + codec->patch_ops = stac92hd71bxx_patch_ops; +#endif spec->stream_delay = 40; /* 40 milliseconds */ + } /* no output amps */ spec->num_pwrs = 0; @@ -4823,11 +4580,15 @@ again: /* disable VSW */ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; - stac_change_pin_config(codec, 0xf, 0x40f000f0); + stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); break; case 0x111d7603: /* 6 Port with Analog Mixer */ - if ((codec->revision_id & 0xf) == 1) + if ((codec->revision_id & 0xf) == 1) { +#ifdef SND_HDA_NEEDS_RESUME + codec->patch_ops = stac92hd71bxx_patch_ops; +#endif spec->stream_delay = 40; /* 40 milliseconds */ + } /* no output amps */ spec->num_pwrs = 0; @@ -4857,7 +4618,7 @@ again: switch (spec->board_config) { case STAC_HP_M4: /* enable internal microphone */ - stac_change_pin_config(codec, 0x0e, 0x01813040); + stac92xx_set_config_reg(codec, 0x0e, 0x01813040); stac92xx_auto_set_pinctl(codec, 0x0e, AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); /* fallthru */ @@ -4902,8 +4663,6 @@ again: return err; } - codec->proc_widget_hook = stac92hd7x_proc_hook; - return 0; }; @@ -4965,12 +4724,14 @@ static int patch_stac922x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac922x_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else if (stac922x_brd_tbl[spec->board_config] != NULL) { + spec->pin_configs = stac922x_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } spec->adc_nids = stac922x_adc_nids; @@ -5033,12 +4794,14 @@ static int patch_stac927x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for" "STAC927x, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac927x_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else { + spec->pin_configs = stac927x_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } spec->digbeep_nid = 0x23; @@ -5068,15 +4831,15 @@ static int patch_stac927x(struct hda_codec *codec) case 0x10280209: case 0x1028022e: /* correct the device field to SPDIF out */ - stac_change_pin_config(codec, 0x21, 0x01442070); + stac92xx_set_config_reg(codec, 0x21, 0x01442070); break; }; /* configure the analog microphone on some laptops */ - stac_change_pin_config(codec, 0x0c, 0x90a79130); + stac92xx_set_config_reg(codec, 0x0c, 0x90a79130); /* correct the front output jack as a hp out */ - stac_change_pin_config(codec, 0x0f, 0x0227011f); + stac92xx_set_config_reg(codec, 0x0f, 0x0227011f); /* correct the front input jack as a mic */ - stac_change_pin_config(codec, 0x0e, 0x02a79130); + stac92xx_set_config_reg(codec, 0x0e, 0x02a79130); /* fallthru */ case STAC_DELL_3ST: /* GPIO2 High = Enable EAPD */ @@ -5124,8 +4887,6 @@ static int patch_stac927x(struct hda_codec *codec) codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac927x_proc_hook; - /* * !!FIXME!! * The STAC927x seem to require fairly long delays for certain @@ -5160,12 +4921,14 @@ static int patch_stac9205(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - } else - err = stac_save_pin_cfgs(codec, - stac9205_brd_tbl[spec->board_config]); - if (err < 0) { - stac92xx_free(codec); - return err; + if (err < 0) { + stac92xx_free(codec); + return err; + } + spec->pin_configs = spec->bios_pin_configs; + } else { + spec->pin_configs = stac9205_brd_tbl[spec->board_config]; + stac92xx_set_config_regs(codec); } spec->digbeep_nid = 0x23; @@ -5192,18 +4955,15 @@ static int patch_stac9205(struct hda_codec *codec) switch (spec->board_config){ case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ - stac_change_pin_config(codec, 0x1f, 0x01441030); - stac_change_pin_config(codec, 0x20, 0x1c410030); + stac92xx_set_config_reg(codec, 0x1f, 0x01441030); + stac92xx_set_config_reg(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ - err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01); - if (err < 0) - return err; snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | err); + (AC_USRSP_EN | STAC_HP_EVENT)); spec->gpio_dir = 0x0b; spec->eapd_mask = 0x01; @@ -5241,8 +5001,6 @@ static int patch_stac9205(struct hda_codec *codec) codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac9205_proc_hook; - return 0; } @@ -5299,11 +5057,29 @@ static struct hda_verb vaio_ar_init[] = { {} }; +/* bind volumes of both NID 0x02 and 0x05 */ +static struct hda_bind_ctls vaio_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +/* bind volumes of both NID 0x02 and 0x05 */ +static struct hda_bind_ctls vaio_bind_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0, + }, +}; + static struct snd_kcontrol_new vaio_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT), + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -5319,10 +5095,8 @@ static struct snd_kcontrol_new vaio_mixer[] = { }; static struct snd_kcontrol_new vaio_ar_mixer[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT), + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -5363,7 +5137,7 @@ static int stac9872_vaio_init(struct hda_codec *codec) static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) { - if (get_pin_presence(codec, 0x0a)) { + if (get_hp_pin_presence(codec, 0x0a)) { stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); } else { @@ -5474,7 +5248,7 @@ static int patch_stac9872(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_sigmatel[] = { +struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, @@ -5538,27 +5312,3 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:8384*"); -MODULE_ALIAS("snd-hda-codec-id:111d*"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec"); - -static struct hda_codec_preset_list sigmatel_list = { - .preset = snd_hda_preset_sigmatel, - .owner = THIS_MODULE, -}; - -static int __init patch_sigmatel_init(void) -{ - return snd_hda_add_codec_preset(&sigmatel_list); -} - -static void __exit patch_sigmatel_exit(void) -{ - snd_hda_delete_codec_preset(&sigmatel_list); -} - -module_init(patch_sigmatel_init) -module_exit(patch_sigmatel_exit) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6e4d01d1d502..63e4871e5d8f 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -47,11 +47,15 @@ #include <sound/asoundef.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" /* amp values */ #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) +#define NUM_CONTROL_ALLOC 32 +#define NUM_VERB_ALLOC 32 + /* Pin Widget NID */ #define VT1708_HP_NID 0x13 #define VT1708_DIGOUT_NID 0x14 @@ -141,6 +145,8 @@ enum { AUTO_SEQ_SIDE }; +#define get_amp_nid(kc) ((kc)->private_value & 0xffff) + /* Some VT1708S based boards gets the micboost setting wrong, so we have * to apply some brute-force and re-write the TLV's by software. */ static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, @@ -221,7 +227,8 @@ struct via_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - struct snd_array kctls; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux[2]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -265,31 +272,33 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return -ENOMEM; + if (spec->num_kctl_used >= spec->num_kctl_alloc) { + int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; + + /* array + terminator */ + knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); + if (!knew) + return -ENOMEM; + if (spec->kctl_alloc) { + memcpy(knew, spec->kctl_alloc, + sizeof(*knew) * spec->num_kctl_alloc); + kfree(spec->kctl_alloc); + } + spec->kctl_alloc = knew; + spec->num_kctl_alloc = num; + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; *knew = vt1708_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); + if (!knew->name) return -ENOMEM; knew->private_value = val; + spec->num_kctl_used++; return 0; } -static void via_free_kctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - /* create input playback/capture controls for the given pin */ static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, const char *ctlname, int idx, int mix_nid) @@ -887,7 +896,6 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err; } - via_free_kctls(codec); /* no longer needed */ return 0; } @@ -933,11 +941,17 @@ static int via_build_pcms(struct hda_codec *codec) static void via_free(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + unsigned int i; if (!spec) return; - via_free_kctls(codec); + if (spec->kctl_alloc) { + for (i = 0; i < spec->num_kctl_used; i++) + kfree(spec->kctl_alloc[i].name); + kfree(spec->kctl_alloc); + } + kfree(codec->spec); } @@ -1359,8 +1373,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1708_DIGIN_NID; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; @@ -1832,8 +1846,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1709_DIGIN_NID; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux[0]; @@ -2376,8 +2390,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1708B_DIGIN_NID; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux[0]; @@ -2841,8 +2855,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->extra_dig_out_nid = 0x15; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux[0]; @@ -3160,8 +3174,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->extra_dig_out_nid = 0x1B; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux[0]; @@ -3248,7 +3262,7 @@ static int patch_vt1702(struct hda_codec *codec) /* * patch entries */ -static struct hda_codec_preset snd_hda_preset_via[] = { +struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, @@ -3319,26 +3333,3 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1702}, {} /* terminator */ }; - -MODULE_ALIAS("snd-hda-codec-id:1106*"); - -static struct hda_codec_preset_list via_list = { - .preset = snd_hda_preset_via, - .owner = THIS_MODULE, -}; - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VIA HD-audio codec"); - -static int __init patch_via_init(void) -{ - return snd_hda_add_codec_preset(&via_list); -} - -static void __exit patch_via_exit(void) -{ - snd_hda_delete_codec_preset(&via_list); -} - -module_init(patch_via_init) -module_exit(patch_via_exit) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 0dfa0540ce2c..1b3f11702713 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -382,25 +382,23 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) unsigned char status_mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM; int handled = 0; +#ifdef CONFIG_SND_DEBUG int timeout = 0; +#endif while (1) { status = inb(ICEREG1724(ice, IRQSTAT)); status &= status_mask; if (status == 0) break; +#ifdef CONFIG_SND_DEBUG if (++timeout > 10) { - status = inb(ICEREG1724(ice, IRQSTAT)); - printk(KERN_ERR "ice1724: Too long irq loop, " - "status = 0x%x\n", status); - if (status & VT1724_IRQ_MPU_TX) { - printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); - outb(inb(ICEREG1724(ice, IRQMASK)) | - VT1724_IRQ_MPU_TX, - ICEREG1724(ice, IRQMASK)); - } + printk(KERN_ERR + "ice1724: Too long irq loop, status = 0x%x\n", + status); break; } +#endif handled = 1; if (status & VT1724_IRQ_MPU_TX) { spin_lock(&ice->reg_lock); @@ -2353,6 +2351,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card, { struct snd_ice1712 *ice; int err; + unsigned char mask; static struct snd_device_ops ops = { .dev_free = snd_vt1724_dev_free, }; @@ -2413,9 +2412,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card, return -EIO; } - /* MPU_RX and TX irq masks are cleared later dynamically */ - outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK)); - + /* unmask used interrupts */ + mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX; + outb(mask, ICEREG1724(ice, IRQMASK)); /* don't handle FIFO overrun/underruns (just yet), * since they cause machine lockups */ diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index f23a73577c22..ae7601f353a7 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1010,7 +1010,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * .dev_free = snd_mixart_chip_dev_free, }; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1025,7 +1025,6 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * return err; } - mgr->chip[idx] = chip; snd_card_set_dev(card, &mgr->pci->dev); return 0; @@ -1378,7 +1377,6 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); if ((err = snd_mixart_create(mgr, card, i)) < 0) { - snd_card_free(card); snd_mixart_free(mgr); return err; } diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index de999c6d6dd3..b60f6212745a 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -61,7 +61,6 @@ MODULE_PARM_DESC(enable, "enable card"); enum { MODEL_CMEDIA_REF, /* C-Media's reference design */ MODEL_MERIDIAN, /* AuzenTech X-Meridian */ - MODEL_HALO, /* HT-Omega Claro halo */ }; static struct pci_device_id oxygen_ids[] __devinitdata = { @@ -75,7 +74,6 @@ static struct pci_device_id oxygen_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF }, - { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO }, { } }; MODULE_DEVICE_TABLE(pci, oxygen_ids); @@ -303,8 +301,6 @@ static int generic_probe(struct oxygen *chip, unsigned long driver_data) PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; - } - if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) { chip->model.misc_flags = OXYGEN_MISC_MIDI; chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; } diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile index b06128e918ca..10473c05918d 100644 --- a/sound/pci/pcxhr/Makefile +++ b/sound/pci/pcxhr/Makefile @@ -1,2 +1,2 @@ -snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o +snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 05a1b6cbd72b..73de6e989b3d 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -40,20 +40,18 @@ #include "pcxhr_mixer.h" #include "pcxhr_hwdep.h" #include "pcxhr_core.h" -#include "pcxhr_mix22.h" #define DRIVER_NAME "pcxhr" -MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>, " - "Marc Titinger <titinger@digigram.com>"); +MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>"); MODULE_DESCRIPTION("Digigram " DRIVER_NAME " " PCXHR_DRIVER_VERSION_STRING); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}"); -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ -static int mono[SNDRV_CARDS]; /* capture mono only */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static int mono[SNDRV_CARDS]; /* capture in mono only */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Digigram " DRIVER_NAME " soundcard"); @@ -69,58 +67,18 @@ enum { PCI_ID_PCX882HR, PCI_ID_VX881HR, PCI_ID_PCX881HR, - PCI_ID_VX882E, - PCI_ID_PCX882E, - PCI_ID_VX881E, - PCI_ID_PCX881E, - PCI_ID_VX1222HR, PCI_ID_PCX1222HR, - PCI_ID_VX1221HR, PCI_ID_PCX1221HR, - PCI_ID_VX1222E, - PCI_ID_PCX1222E, - PCI_ID_VX1221E, - PCI_ID_PCX1221E, - PCI_ID_VX222HR, - PCI_ID_VX222E, - PCI_ID_PCX22HR, - PCI_ID_PCX22E, - PCI_ID_VX222HRMIC, - PCI_ID_VX222E_MIC, - PCI_ID_PCX924HR, - PCI_ID_PCX924E, - PCI_ID_PCX924HRMIC, - PCI_ID_PCX924E_MIC, PCI_ID_LAST }; static struct pci_device_id pcxhr_ids[] = { - { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, - { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, - { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, - { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, }, - { 0x10b5, 0x9056, 0x1369, 0xb021, 0, 0, PCI_ID_VX882E, }, - { 0x10b5, 0x9056, 0x1369, 0xb121, 0, 0, PCI_ID_PCX882E, }, - { 0x10b5, 0x9056, 0x1369, 0xb221, 0, 0, PCI_ID_VX881E, }, - { 0x10b5, 0x9056, 0x1369, 0xb321, 0, 0, PCI_ID_PCX881E, }, - { 0x10b5, 0x9656, 0x1369, 0xb401, 0, 0, PCI_ID_VX1222HR, }, - { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, - { 0x10b5, 0x9656, 0x1369, 0xb601, 0, 0, PCI_ID_VX1221HR, }, - { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, - { 0x10b5, 0x9056, 0x1369, 0xb421, 0, 0, PCI_ID_VX1222E, }, - { 0x10b5, 0x9056, 0x1369, 0xb521, 0, 0, PCI_ID_PCX1222E, }, - { 0x10b5, 0x9056, 0x1369, 0xb621, 0, 0, PCI_ID_VX1221E, }, - { 0x10b5, 0x9056, 0x1369, 0xb721, 0, 0, PCI_ID_PCX1221E, }, - { 0x10b5, 0x9056, 0x1369, 0xba01, 0, 0, PCI_ID_VX222HR, }, - { 0x10b5, 0x9056, 0x1369, 0xba21, 0, 0, PCI_ID_VX222E, }, - { 0x10b5, 0x9056, 0x1369, 0xbd01, 0, 0, PCI_ID_PCX22HR, }, - { 0x10b5, 0x9056, 0x1369, 0xbd21, 0, 0, PCI_ID_PCX22E, }, - { 0x10b5, 0x9056, 0x1369, 0xbc01, 0, 0, PCI_ID_VX222HRMIC, }, - { 0x10b5, 0x9056, 0x1369, 0xbc21, 0, 0, PCI_ID_VX222E_MIC, }, - { 0x10b5, 0x9056, 0x1369, 0xbb01, 0, 0, PCI_ID_PCX924HR, }, - { 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, }, - { 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, }, - { 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, }, + { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, /* VX882HR */ + { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, /* PCX882HR */ + { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, /* VX881HR */ + { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, }, /* PCX881HR */ + { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, /* PCX1222HR */ + { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, /* PCX1221HR */ { 0, } }; @@ -130,55 +88,27 @@ struct board_parameters { char* board_name; short playback_chips; short capture_chips; - short fw_file_set; short firmware_num; }; static struct board_parameters pcxhr_board_params[] = { -[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 0, 41 }, -[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 0, 41 }, -[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 0, 41 }, -[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 0, 41 }, -[PCI_ID_VX882E] = { "VX882e", 4, 4, 1, 41 }, -[PCI_ID_PCX882E] = { "PCX882e", 4, 4, 1, 41 }, -[PCI_ID_VX881E] = { "VX881e", 4, 4, 1, 41 }, -[PCI_ID_PCX881E] = { "PCX881e", 4, 4, 1, 41 }, -[PCI_ID_VX1222HR] = { "VX1222HR", 6, 1, 2, 42 }, -[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 2, 42 }, -[PCI_ID_VX1221HR] = { "VX1221HR", 6, 1, 2, 42 }, -[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 2, 42 }, -[PCI_ID_VX1222E] = { "VX1222e", 6, 1, 3, 42 }, -[PCI_ID_PCX1222E] = { "PCX1222e", 6, 1, 3, 42 }, -[PCI_ID_VX1221E] = { "VX1221e", 6, 1, 3, 42 }, -[PCI_ID_PCX1221E] = { "PCX1221e", 6, 1, 3, 42 }, -[PCI_ID_VX222HR] = { "VX222HR", 1, 1, 4, 44 }, -[PCI_ID_VX222E] = { "VX222e", 1, 1, 4, 44 }, -[PCI_ID_PCX22HR] = { "PCX22HR", 1, 0, 4, 44 }, -[PCI_ID_PCX22E] = { "PCX22e", 1, 0, 4, 44 }, -[PCI_ID_VX222HRMIC] = { "VX222HR-Mic", 1, 1, 5, 44 }, -[PCI_ID_VX222E_MIC] = { "VX222e-Mic", 1, 1, 5, 44 }, -[PCI_ID_PCX924HR] = { "PCX924HR", 1, 1, 5, 44 }, -[PCI_ID_PCX924E] = { "PCX924e", 1, 1, 5, 44 }, -[PCI_ID_PCX924HRMIC] = { "PCX924HR-Mic", 1, 1, 5, 44 }, -[PCI_ID_PCX924E_MIC] = { "PCX924e-Mic", 1, 1, 5, 44 }, +[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 41, }, +[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 41, }, +[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 41, }, +[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 41, }, +[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 42, }, +[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 42, }, }; -/* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */ -/* VX222HR, VX222e, PCX22HR and PCX22e */ -#define PCXHR_BOARD_HAS_AES1(x) (x->fw_file_set != 4) -/* some boards do not support 192kHz on digital AES input plugs */ -#define PCXHR_BOARD_AESIN_NO_192K(x) ((x->capture_chips == 0) || \ - (x->fw_file_set == 0) || \ - (x->fw_file_set == 2)) static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, unsigned int* realfreq) { unsigned int reg; - if (freq < 6900 || freq > 110000) + if (freq < 6900 || freq > 110250) return -EINVAL; - reg = (28224000 * 2) / freq; - reg = (reg - 1) / 2; + reg = (28224000 * 10) / freq; + reg = (reg + 5) / 10; if (reg < 0x200) *pllreg = reg + 0x800; else if (reg < 0x400) @@ -191,7 +121,7 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, reg &= ~3; } if (realfreq) - *realfreq = (28224000 / (reg + 1)); + *realfreq = ((28224000 * 10) / reg + 5) / 10; return 0; } @@ -221,6 +151,11 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, #define PCXHR_FREQ_AES_3 0x03 #define PCXHR_FREQ_AES_4 0x0d +#define PCXHR_MODIFY_CLOCK_S_BIT 0x04 + +#define PCXHR_IRQ_TIMER_FREQ 92000 +#define PCXHR_IRQ_TIMER_PERIOD 48 + static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, unsigned int *reg, unsigned int *freq) { @@ -261,32 +196,19 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { snd_printk(KERN_ERR - "error CMD_ACCESS_IO_WRITE " - "for PLL register : %x!\n", err); + "error CMD_ACCESS_IO_WRITE for PLL register : %x!\n", + err ); return err; } } break; - case PCXHR_CLOCK_TYPE_WORD_CLOCK: - val = PCXHR_FREQ_WORD_CLOCK; - break; - case PCXHR_CLOCK_TYPE_AES_SYNC: - val = PCXHR_FREQ_SYNC_AES; - break; - case PCXHR_CLOCK_TYPE_AES_1: - val = PCXHR_FREQ_AES_1; - break; - case PCXHR_CLOCK_TYPE_AES_2: - val = PCXHR_FREQ_AES_2; - break; - case PCXHR_CLOCK_TYPE_AES_3: - val = PCXHR_FREQ_AES_3; - break; - case PCXHR_CLOCK_TYPE_AES_4: - val = PCXHR_FREQ_AES_4; - break; - default: - return -EINVAL; + case PCXHR_CLOCK_TYPE_WORD_CLOCK : val = PCXHR_FREQ_WORD_CLOCK; break; + case PCXHR_CLOCK_TYPE_AES_SYNC : val = PCXHR_FREQ_SYNC_AES; break; + case PCXHR_CLOCK_TYPE_AES_1 : val = PCXHR_FREQ_AES_1; break; + case PCXHR_CLOCK_TYPE_AES_2 : val = PCXHR_FREQ_AES_2; break; + case PCXHR_CLOCK_TYPE_AES_3 : val = PCXHR_FREQ_AES_3; break; + case PCXHR_CLOCK_TYPE_AES_4 : val = PCXHR_FREQ_AES_4; break; + default : return -EINVAL; } *reg = val; *freq = realfreq; @@ -294,13 +216,14 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, } -static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr, - unsigned int rate, - int *changed) +int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) { unsigned int val, realfreq, speed; struct pcxhr_rmh rmh; - int err; + int err, changed; + + if (rate == 0) + return 0; /* nothing to do */ err = pcxhr_get_clock_reg(mgr, rate, &val, &realfreq); if (err) @@ -314,17 +237,13 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr, else speed = 2; /* quad speed */ if (mgr->codec_speed != speed) { - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; - if (DSP_EXT_CMD_SET(mgr)) { - rmh.cmd[1] = 1; - rmh.cmd_len = 2; - } err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */ rmh.cmd[0] |= IO_NUM_SPEED_RATIO; rmh.cmd[1] = speed; rmh.cmd_len = 2; @@ -334,57 +253,25 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr, } /* set the new frequency */ snd_printdd("clock register : set %x\n", val); - err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, - val, changed); + err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, val, &changed); if (err) return err; - mgr->sample_rate_real = realfreq; mgr->cur_clock_type = mgr->use_clock_type; /* unmute after codec speed modes */ if (mgr->codec_speed != speed) { - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; - if (DSP_EXT_CMD_SET(mgr)) { - rmh.cmd[1] = 1; - rmh.cmd_len = 2; - } err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - mgr->codec_speed = speed; /* save new codec speed */ + mgr->codec_speed = speed; /* save new codec speed */ } - snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n", - rate, realfreq); - return 0; -} - -#define PCXHR_MODIFY_CLOCK_S_BIT 0x04 - -#define PCXHR_IRQ_TIMER_FREQ 92000 -#define PCXHR_IRQ_TIMER_PERIOD 48 - -int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) -{ - struct pcxhr_rmh rmh; - int err, changed; - - if (rate == 0) - return 0; /* nothing to do */ - - if (mgr->is_hr_stereo) - err = hr222_sub_set_clock(mgr, rate, &changed); - else - err = pcxhr_sub_set_clock(mgr, rate, &changed); - - if (err) - return err; - if (changed) { pcxhr_init_rmh(&rmh, CMD_MODIFY_CLOCK); - rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */ + rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */ if (rate < PCXHR_IRQ_TIMER_FREQ) rmh.cmd[1] = PCXHR_IRQ_TIMER_PERIOD; else @@ -395,39 +282,26 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) if (err) return err; } + snd_printdd("pcxhr_set_clock to %dHz (realfreq=%d)\n", rate, realfreq); return 0; } -static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr, - enum pcxhr_clock_type clock_type, - int *sample_rate) +int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, + int *sample_rate) { struct pcxhr_rmh rmh; unsigned char reg; int err, rate; switch (clock_type) { - case PCXHR_CLOCK_TYPE_WORD_CLOCK: - reg = REG_STATUS_WORD_CLOCK; - break; - case PCXHR_CLOCK_TYPE_AES_SYNC: - reg = REG_STATUS_AES_SYNC; - break; - case PCXHR_CLOCK_TYPE_AES_1: - reg = REG_STATUS_AES_1; - break; - case PCXHR_CLOCK_TYPE_AES_2: - reg = REG_STATUS_AES_2; - break; - case PCXHR_CLOCK_TYPE_AES_3: - reg = REG_STATUS_AES_3; - break; - case PCXHR_CLOCK_TYPE_AES_4: - reg = REG_STATUS_AES_4; - break; - default: - return -EINVAL; + case PCXHR_CLOCK_TYPE_WORD_CLOCK : reg = REG_STATUS_WORD_CLOCK; break; + case PCXHR_CLOCK_TYPE_AES_SYNC : reg = REG_STATUS_AES_SYNC; break; + case PCXHR_CLOCK_TYPE_AES_1 : reg = REG_STATUS_AES_1; break; + case PCXHR_CLOCK_TYPE_AES_2 : reg = REG_STATUS_AES_2; break; + case PCXHR_CLOCK_TYPE_AES_3 : reg = REG_STATUS_AES_3; break; + case PCXHR_CLOCK_TYPE_AES_4 : reg = REG_STATUS_AES_4; break; + default : return -EINVAL; } pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd_len = 2; @@ -437,7 +311,7 @@ static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr, err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */ + udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */ mgr->last_reg_stat = reg; } rmh.cmd[1] = REG_STATUS_CURRENT; @@ -462,18 +336,6 @@ static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr, } -int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, - enum pcxhr_clock_type clock_type, - int *sample_rate) -{ - if (mgr->is_hr_stereo) - return hr222_get_external_clock(mgr, clock_type, - sample_rate); - else - return pcxhr_sub_get_external_clock(mgr, clock_type, - sample_rate); -} - /* * start or stop playback/capture substream */ @@ -488,8 +350,7 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) start = 1; else { if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) { - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state " - "CANNOT be stopped\n"); + snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state CANNOT be stopped\n"); return -EINVAL; } start = 0; @@ -498,12 +359,11 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) return -EINVAL; stream->timer_abs_periods = 0; - stream->timer_period_frag = 0; /* reset theoretical stream pos */ + stream->timer_period_frag = 0; /* reset theoretical stream pos */ stream->timer_buf_periods = 0; stream->timer_is_synced = 0; - stream_mask = - stream->pipe->is_capture ? 1 : 1<<stream->substream->number; + stream_mask = stream->pipe->is_capture ? 1 : 1<<stream->substream->number; pcxhr_init_rmh(&rmh, start ? CMD_START_STREAM : CMD_STOP_STREAM); pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture, @@ -513,10 +373,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", - err); - stream->status = - start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED; + snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", err); + stream->status = start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED; return err; } @@ -541,15 +399,13 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) header = HEADER_FMT_BASE_LIN; break; case SNDRV_PCM_FORMAT_S16_LE: - header = HEADER_FMT_BASE_LIN | - HEADER_FMT_16BITS | HEADER_FMT_INTEL; + header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS | HEADER_FMT_INTEL; break; case SNDRV_PCM_FORMAT_S16_BE: header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS; break; case SNDRV_PCM_FORMAT_S24_3LE: - header = HEADER_FMT_BASE_LIN | - HEADER_FMT_24BITS | HEADER_FMT_INTEL; + header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS | HEADER_FMT_INTEL; break; case SNDRV_PCM_FORMAT_S24_3BE: header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS; @@ -558,8 +414,7 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL; break; default: - snd_printk(KERN_ERR - "error pcxhr_set_format() : unknown format\n"); + snd_printk(KERN_ERR "error pcxhr_set_format() : unknown format\n"); return -EINVAL; } chip = snd_pcm_substream_chip(stream->substream); @@ -577,31 +432,14 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) is_capture = stream->pipe->is_capture; stream_num = is_capture ? 0 : stream->substream->number; - pcxhr_init_rmh(&rmh, is_capture ? - CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, - stream_num, 0); - if (is_capture) { - /* bug with old dsp versions: */ - /* bit 12 also sets the format of the playback stream */ - if (DSP_EXT_CMD_SET(chip->mgr)) - rmh.cmd[0] |= 1<<10; - else - rmh.cmd[0] |= 1<<12; - } + pcxhr_init_rmh(&rmh, is_capture ? CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0); + if (is_capture) + rmh.cmd[0] |= 1<<12; rmh.cmd[1] = 0; - rmh.cmd_len = 2; - if (DSP_EXT_CMD_SET(chip->mgr)) { - /* add channels and set bit 19 if channels>2 */ - rmh.cmd[1] = stream->channels; - if (!is_capture) { - /* playback : add channel mask to command */ - rmh.cmd[2] = (stream->channels == 1) ? 0x01 : 0x03; - rmh.cmd_len = 3; - } - } - rmh.cmd[rmh.cmd_len++] = header >> 8; - rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16; + rmh.cmd[2] = header >> 8; + rmh.cmd[3] = (header & 0xff) << 16; + rmh.cmd_len = 4; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err); @@ -618,38 +456,30 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream) is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE); stream_num = is_capture ? 0 : subs->number; - snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : " - "addr(%p) bytes(%zx) subs(%d)\n", + snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n", is_capture ? 'c' : 'p', chip->chip_idx, (void *)(long)subs->runtime->dma_addr, subs->runtime->dma_bytes, subs->number); pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, - stream_num, 0); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0); /* max buffer size is 2 MByte */ snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000); - /* size in bits */ - rmh.cmd[1] = subs->runtime->dma_bytes * 8; - /* most significant byte */ - rmh.cmd[2] = subs->runtime->dma_addr >> 24; - /* this is a circular buffer */ - rmh.cmd[2] |= 1<<19; - /* least 3 significant bytes */ - rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD; + rmh.cmd[1] = subs->runtime->dma_bytes * 8; /* size in bits */ + rmh.cmd[2] = subs->runtime->dma_addr >> 24; /* most significant byte */ + rmh.cmd[2] |= 1<<19; /* this is a circular buffer */ + rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD; /* least 3 significant bytes */ rmh.cmd_len = 4; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR - "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err); + snd_printk(KERN_ERR "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err); return err; } #if 0 -static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, - snd_pcm_uframes_t *sample_count) +static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, snd_pcm_uframes_t *sample_count) { struct pcxhr_rmh rmh; int err; @@ -703,8 +533,8 @@ static void pcxhr_trigger_tasklet(unsigned long arg) for (j = 0; j < chip->nb_streams_play; j++) { if (pcxhr_stream_scheduled_get_pipe(&chip->playback_stream[j], &pipe)) { playback_mask |= (1 << pipe->first_audio); - break; /* add only once, as all playback - * streams of one chip use the same pipe + break; /* add only once, as all playback streams of + * one chip use the same pipe */ } } @@ -715,21 +545,19 @@ static void pcxhr_trigger_tasklet(unsigned long arg) return; } - snd_printdd("pcxhr_trigger_tasklet : " - "playback_mask=%x capture_mask=%x\n", + snd_printdd("pcxhr_trigger_tasklet : playback_mask=%x capture_mask=%x\n", playback_mask, capture_mask); /* synchronous stop of all the pipes concerned */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " - "error stop pipes (P%x C%x)\n", + snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n", playback_mask, capture_mask); return; } - /* the dsp lost format and buffer info with the stop pipe */ + /* unfortunately the dsp lost format and buffer info with the stop pipe */ for (i = 0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; chip = mgr->chip[i]; @@ -768,15 +596,12 @@ static void pcxhr_trigger_tasklet(unsigned long arg) err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " - "error start pipes (P%x C%x)\n", + snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n", playback_mask, capture_mask); return; } - /* put the streams into the running state now - * (increment pointer by interrupt) - */ + /* put the streams into the running state now (increment pointer by interrupt) */ spin_lock_irqsave(&mgr->lock, flags); for ( i =0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; @@ -790,7 +615,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) stream = &chip->playback_stream[j]; if (stream->status == PCXHR_STREAM_STATUS_STARTED) { /* playback will already have advanced ! */ - stream->timer_period_frag += mgr->granularity; + stream->timer_period_frag += PCXHR_GRANULARITY; stream->status = PCXHR_STREAM_STATUS_RUNNING; } } @@ -872,14 +697,12 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start) pcxhr_init_rmh(&rmh, CMD_SET_TIMER_INTERRUPT); if (start) { - /* last dsp time invalid */ - mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; - rmh.cmd[0] |= mgr->granularity; + mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; /* last dsp time invalid */ + rmh.cmd[0] |= PCXHR_GRANULARITY; } err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", - err); + snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", err); return err; } @@ -890,16 +713,38 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) { struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); struct pcxhr_mgr *mgr = chip->mgr; + /* + struct pcxhr_stream *stream = (pcxhr_stream_t*)subs->runtime->private_data; + */ int err = 0; snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n", subs->runtime->period_size, subs->runtime->periods, subs->runtime->buffer_size); + /* + if(subs->runtime->period_size <= PCXHR_GRANULARITY) { + snd_printk(KERN_ERR "pcxhr_prepare : error period_size too small (%x)\n", + (unsigned int)subs->runtime->period_size); + return -EINVAL; + } + */ + mutex_lock(&mgr->setup_mutex); do { + /* if the stream was stopped before, format and buffer were reset */ + /* + if(stream->status == PCXHR_STREAM_STATUS_STOPPED) { + err = pcxhr_set_format(stream); + if(err) break; + err = pcxhr_update_r_buffer(stream); + if(err) break; + } + */ + /* only the first stream can choose the sample rate */ + /* the further opened streams will be limited to its frequency (see open) */ /* set the clock only once (first stream) */ if (mgr->sample_rate != subs->runtime->rate) { err = pcxhr_set_clock(mgr, subs->runtime->rate); @@ -942,9 +787,22 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs, stream->channels = channels; stream->format = format; + /* set the format to the board */ + /* + err = pcxhr_set_format(stream); + if(err) { + mutex_unlock(&mgr->setup_mutex); + return err; + } + */ /* allocate buffer */ err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw)); + /* + if (err > 0) { + err = pcxhr_update_r_buffer(stream); + } + */ mutex_unlock(&mgr->setup_mutex); return err; @@ -962,18 +820,14 @@ static int pcxhr_hw_free(struct snd_pcm_substream *subs) */ static struct snd_pcm_hardware pcxhr_caps = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_START), - .formats = (SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S24_3BE | - SNDRV_PCM_FMTBIT_FLOAT_LE), - .rates = (SNDRV_PCM_RATE_CONTINUOUS | - SNDRV_PCM_RATE_8000_192000), + .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | + 0 /*SNDRV_PCM_INFO_PAUSE*/), + .formats = ( SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | + SNDRV_PCM_FMTBIT_FLOAT_LE ), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, .rate_max = 192000, .channels_min = 1, @@ -993,7 +847,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs) struct pcxhr_mgr *mgr = chip->mgr; struct snd_pcm_runtime *runtime = subs->runtime; struct pcxhr_stream *stream; - int err; mutex_lock(&mgr->setup_mutex); @@ -1021,18 +874,6 @@ static int pcxhr_open(struct snd_pcm_substream *subs) return -EBUSY; } - /* float format support is in some cases buggy on stereo cards */ - if (mgr->is_hr_stereo) - runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_FLOAT_LE; - - /* buffer-size should better be multiple of period-size */ - err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - mutex_unlock(&mgr->setup_mutex); - return err; - } - /* if a sample rate is already used or fixed by external clock, * the stream cannot change */ @@ -1048,8 +889,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) mutex_unlock(&mgr->setup_mutex); return -EBUSY; } - runtime->hw.rate_min = external_rate; - runtime->hw.rate_max = external_rate; + runtime->hw.rate_min = runtime->hw.rate_max = external_rate; } } @@ -1059,11 +899,9 @@ static int pcxhr_open(struct snd_pcm_substream *subs) runtime->private_data = stream; - /* better get a divisor of granularity values (96 or 192) */ - snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); - snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); + snd_pcm_set_sync(subs); mgr->ref_count_rate++; @@ -1081,12 +919,11 @@ static int pcxhr_close(struct snd_pcm_substream *subs) mutex_lock(&mgr->setup_mutex); - snd_printdd("pcxhr_close chip%d subs%d\n", - chip->chip_idx, subs->number); + snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number); /* sample rate released */ if (--mgr->ref_count_rate == 0) { - mgr->sample_rate = 0; /* the sample rate is no more locked */ + mgr->sample_rate = 0; /* the sample rate is no more locked */ pcxhr_hardware_timer(mgr, 0); /* stop the DSP-timer */ } @@ -1179,8 +1016,7 @@ static int pcxhr_chip_dev_free(struct snd_device *device) /* */ -static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, - struct snd_card *card, int idx) +static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, int idx) { int err; struct snd_pcxhr *chip; @@ -1188,7 +1024,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, .dev_free = pcxhr_chip_dev_free, }; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1204,7 +1040,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, if (idx < mgr->capture_chips) { if (mgr->mono_capture) - chip->nb_streams_capt = 2; /* 2 mono streams */ + chip->nb_streams_capt = 2; /* 2 mono streams (left+right) */ else chip->nb_streams_capt = 1; /* or 1 stereo stream */ } @@ -1214,15 +1050,13 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, return err; } - mgr->chip[idx] = chip; snd_card_set_dev(card, &mgr->pci->dev); return 0; } /* proc interface */ -static void pcxhr_proc_info(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; @@ -1235,10 +1069,8 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, short ver_maj = (mgr->dsp_version >> 16) & 0xff; short ver_min = (mgr->dsp_version >> 8) & 0xff; short ver_build = mgr->dsp_version & 0xff; - snd_iprintf(buffer, "module version %s\n", - PCXHR_DRIVER_VERSION_STRING); - snd_iprintf(buffer, "dsp version %d.%d.%d\n", - ver_maj, ver_min, ver_build); + snd_iprintf(buffer, "module version %s\n", PCXHR_DRIVER_VERSION_STRING); + snd_iprintf(buffer, "dsp version %d.%d.%d\n", ver_maj, ver_min, ver_build); if (mgr->board_has_analog) snd_iprintf(buffer, "analog io available\n"); else @@ -1252,22 +1084,18 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, if (ref > 0) { if (mgr->sample_rate_real != 0 && mgr->sample_rate_real != 48000) { - ref = (ref * 48000) / - mgr->sample_rate_real; - if (mgr->sample_rate_real >= - PCXHR_IRQ_TIMER_FREQ) + ref = (ref * 48000) / mgr->sample_rate_real; + if (mgr->sample_rate_real >= PCXHR_IRQ_TIMER_FREQ) ref *= 2; } cur = 100 - (100 * cur) / ref; snd_iprintf(buffer, "cpu load %d%%\n", cur); - snd_iprintf(buffer, "buffer pool %d/%d\n", + snd_iprintf(buffer, "buffer pool %d/%d kWords\n", rmh.stat[2], rmh.stat[3]); } } - snd_iprintf(buffer, "dma granularity : %d\n", - mgr->granularity); - snd_iprintf(buffer, "dsp time errors : %d\n", - mgr->dsp_time_err); + snd_iprintf(buffer, "dma granularity : %d\n", PCXHR_GRANULARITY); + snd_iprintf(buffer, "dsp time errors : %d\n", mgr->dsp_time_err); snd_iprintf(buffer, "dsp async pipe xrun errors : %d\n", mgr->async_err_pipe_xrun); snd_iprintf(buffer, "dsp async stream xrun errors : %d\n", @@ -1282,52 +1110,33 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, rmh.cmd_idx = CMD_LAST_INDEX; if( ! pcxhr_send_msg(mgr, &rmh) ) { int i; - if (rmh.stat_len > 8) - rmh.stat_len = 8; for (i = 0; i < rmh.stat_len; i++) - snd_iprintf(buffer, "debug[%02d] = %06x\n", - i, rmh.stat[i]); + snd_iprintf(buffer, "debug[%02d] = %06x\n", i, rmh.stat[i]); } } else snd_iprintf(buffer, "no firmware loaded\n"); snd_iprintf(buffer, "\n"); } -static void pcxhr_proc_sync(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +static void pcxhr_proc_sync(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; - static const char *textsHR22[3] = { - "Internal", "AES Sync", "AES 1" - }; - static const char *textsPCXHR[7] = { - "Internal", "Word", "AES Sync", - "AES 1", "AES 2", "AES 3", "AES 4" + static char *texts[7] = { + "Internal", "Word", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" }; - const char **texts; - int max_clock; - if (mgr->is_hr_stereo) { - texts = textsHR22; - max_clock = HR22_CLOCK_TYPE_MAX; - } else { - texts = textsPCXHR; - max_clock = PCXHR_CLOCK_TYPE_MAX; - } snd_iprintf(buffer, "\n%s\n", mgr->longname); - snd_iprintf(buffer, "Current Sample Clock\t: %s\n", - texts[mgr->cur_clock_type]); - snd_iprintf(buffer, "Current Sample Rate\t= %d\n", - mgr->sample_rate_real); + snd_iprintf(buffer, "Current Sample Clock\t: %s\n", texts[mgr->cur_clock_type]); + snd_iprintf(buffer, "Current Sample Rate\t= %d\n", mgr->sample_rate_real); + /* commands available when embedded DSP is running */ if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { int i, err, sample_rate; - for (i = 1; i <= max_clock; i++) { + for (i = PCXHR_CLOCK_TYPE_WORD_CLOCK; i< (3 + mgr->capture_chips); i++) { err = pcxhr_get_external_clock(mgr, i, &sample_rate); if (err) break; - snd_iprintf(buffer, "%s Clock\t\t= %d\n", - texts[i], sample_rate); + snd_iprintf(buffer, "%s Clock\t\t= %d\n", texts[i], sample_rate); } } else snd_iprintf(buffer, "no firmware loaded\n"); @@ -1385,8 +1194,7 @@ static int pcxhr_free(struct pcxhr_mgr *mgr) /* * probe function - creates the card manager */ -static int __devinit pcxhr_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; struct pcxhr_mgr *mgr; @@ -1409,8 +1217,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, /* check if we can restrict PCI DMA transfers to 32 bits */ if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) { - snd_printk(KERN_ERR "architecture does not support " - "32bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1427,25 +1234,11 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, pci_disable_device(pci); return -ENODEV; } - card_name = - pcxhr_board_params[pci_id->driver_data].board_name; - mgr->playback_chips = - pcxhr_board_params[pci_id->driver_data].playback_chips; - mgr->capture_chips = - pcxhr_board_params[pci_id->driver_data].capture_chips; - mgr->fw_file_set = - pcxhr_board_params[pci_id->driver_data].fw_file_set; - mgr->firmware_num = - pcxhr_board_params[pci_id->driver_data].firmware_num; + card_name = pcxhr_board_params[pci_id->driver_data].board_name; + mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips; + mgr->capture_chips = pcxhr_board_params[pci_id->driver_data].capture_chips; + mgr->firmware_num = pcxhr_board_params[pci_id->driver_data].firmware_num; mgr->mono_capture = mono[dev]; - mgr->is_hr_stereo = (mgr->playback_chips == 1); - mgr->board_has_aes1 = PCXHR_BOARD_HAS_AES1(mgr); - mgr->board_aes_in_192k = !PCXHR_BOARD_AESIN_NO_192K(mgr); - - if (mgr->is_hr_stereo) - mgr->granularity = PCXHR_GRANULARITY_HR22; - else - mgr->granularity = PCXHR_GRANULARITY; /* resource assignment */ if ((err = pci_request_regions(pci, card_name)) < 0) { @@ -1468,8 +1261,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, mgr->irq = pci->irq; sprintf(mgr->shortname, "Digigram %s", card_name); - sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", - mgr->shortname, + sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", mgr->shortname, mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq); /* ISR spinlock */ @@ -1480,14 +1272,10 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, mutex_init(&mgr->setup_mutex); /* init taslket */ - tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, - (unsigned long) mgr); - tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, - (unsigned long) mgr); - + tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr); + tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, (unsigned long) mgr); mgr->prmh = kmalloc(sizeof(*mgr->prmh) + - sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - - PCXHR_SIZE_MAX_STATUS), + sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS), GFP_KERNEL); if (! mgr->prmh) { pcxhr_free(mgr); @@ -1508,8 +1296,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, else idx = index[dev] + i; - snprintf(tmpid, sizeof(tmpid), "%s-%d", - id[dev] ? id[dev] : card_name, i); + snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i); card = snd_card_new(idx, tmpid, THIS_MODULE, 0); if (! card) { @@ -1523,7 +1310,6 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); if ((err = pcxhr_create(mgr, card, i)) < 0) { - snd_card_free(card); pcxhr_free(mgr); return err; } diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h index 84131a916c92..652064787a55 100644 --- a/sound/pci/pcxhr/pcxhr.h +++ b/sound/pci/pcxhr/pcxhr.h @@ -27,18 +27,15 @@ #include <linux/mutex.h> #include <sound/pcm.h> -#define PCXHR_DRIVER_VERSION 0x000905 /* 0.9.5 */ -#define PCXHR_DRIVER_VERSION_STRING "0.9.5" /* 0.9.5 */ +#define PCXHR_DRIVER_VERSION 0x000804 /* 0.8.4 */ +#define PCXHR_DRIVER_VERSION_STRING "0.8.4" /* 0.8.4 */ -#define PCXHR_MAX_CARDS 6 -#define PCXHR_PLAYBACK_STREAMS 4 +#define PCXHR_MAX_CARDS 6 +#define PCXHR_PLAYBACK_STREAMS 4 -#define PCXHR_GRANULARITY 96 /* min 96 and multiple of 48 */ -/* transfer granularity of pipes and the dsp time (MBOX4) */ -#define PCXHR_GRANULARITY_MIN 96 -/* TODO : granularity could be 64 or 128 */ -#define PCXHR_GRANULARITY_HR22 192 /* granularity for stereo cards */ +#define PCXHR_GRANULARITY 96 /* transfer granularity (should be min 96 and multiple of 48) */ +#define PCXHR_GRANULARITY_MIN 96 /* transfer granularity of pipes and the dsp time (MBOX4) */ struct snd_pcxhr; struct pcxhr_mgr; @@ -54,11 +51,6 @@ enum pcxhr_clock_type { PCXHR_CLOCK_TYPE_AES_2, PCXHR_CLOCK_TYPE_AES_3, PCXHR_CLOCK_TYPE_AES_4, - PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, - HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, - HR22_CLOCK_TYPE_AES_SYNC, - HR22_CLOCK_TYPE_AES_1, - HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, }; struct pcxhr_mgr { @@ -69,8 +61,6 @@ struct pcxhr_mgr { int irq; - int granularity; - /* card access with 1 mem bar and 2 io bar's */ unsigned long port[3]; @@ -93,16 +83,11 @@ struct pcxhr_mgr { /* hardware interface */ unsigned int dsp_loaded; /* bit flags of loaded dsp indices */ unsigned int dsp_version; /* read from embedded once firmware is loaded */ - int playback_chips; - int capture_chips; - int fw_file_set; - int firmware_num; - int is_hr_stereo:1; - int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */ - int board_has_analog:1; /* if 0 the board is digital only */ - int board_has_mic:1; /* if 1 the board has microphone input */ - int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */ - int mono_capture:1; /* if 1 the board does mono capture */ + int board_has_analog; /* if 0 the board is digital only */ + int mono_capture; /* if 1 the board does mono capture */ + int playback_chips; /* 4 or 6 */ + int capture_chips; /* 4 or 1 */ + int firmware_num; /* 41 or 42 */ struct snd_dma_buffer hostport; @@ -121,9 +106,6 @@ struct pcxhr_mgr { int async_err_stream_xrun; int async_err_pipe_xrun; int async_err_other_last; - - unsigned char xlx_cfg; /* copy of PCXHR_XLX_CFG register */ - unsigned char xlx_selmic; /* copy of PCXHR_XLX_SELMIC register */ }; @@ -173,30 +155,24 @@ struct snd_pcxhr { struct snd_pcm *pcm; /* PCM */ - struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */ - struct pcxhr_pipe capture_pipe[2]; /* 1 stereo or 2 mono pipes */ + struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */ + struct pcxhr_pipe capture_pipe[2]; /* 1 stereo pipe or 2 mono pipes */ struct pcxhr_stream playback_stream[PCXHR_PLAYBACK_STREAMS]; - struct pcxhr_stream capture_stream[2]; /* 1 stereo or 2 mono streams */ + struct pcxhr_stream capture_stream[2]; /* 1 stereo stream or 2 mono streams */ int nb_streams_play; int nb_streams_capt; - int analog_playback_active[2]; /* Mixer : Master Playback !mute */ - int analog_playback_volume[2]; /* Mixer : Master Playback Volume */ - int analog_capture_volume[2]; /* Mixer : Master Capture Volume */ - int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; - int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; - int digital_capture_volume[2]; /* Mixer : Digital Capture Volume */ - int monitoring_active[2]; /* Mixer : Monitoring Active */ - int monitoring_volume[2]; /* Mixer : Monitoring Volume */ - int audio_capture_source; /* Mixer : Audio Capture Source */ - int mic_volume; /* used by cards with MIC only */ - int mic_boost; /* used by cards with MIC only */ - int mic_active; /* used by cards with MIC only */ - int analog_capture_active; /* used by cards with MIC only */ - int phantom_power; /* used by cards with MIC only */ - - unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */ + int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */ + int analog_playback_volume[2]; /* Mixer : Master Playback Volume */ + int analog_capture_volume[2]; /* Mixer : Master Capture Volume */ + int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [streams][stereo]*/ + int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [streams][stereo]*/ + int digital_capture_volume[2]; /* Mixer : Digital Capture Volume [stereo] */ + int monitoring_active[2]; /* Mixer : Monitoring Active */ + int monitoring_volume[2]; /* Mixer : Monitoring Volume */ + int audio_capture_source; /* Mixer : Audio Capture Source */ + unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */ }; struct pcxhr_hostport @@ -208,8 +184,6 @@ struct pcxhr_hostport /* exported */ int pcxhr_create_pcm(struct snd_pcxhr *chip); int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate); -int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, - enum pcxhr_clock_type clock_type, - int *sample_rate); +int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, int *sample_rate); #endif /* __SOUND_PCXHR_H */ diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index d5f18226261d..7143259cfe34 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -132,15 +132,13 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg, *read = PCXHR_INPB(mgr, reg); if ((*read & mask) == bit) { if (i > 100) - snd_printdd("ATTENTION! check_reg(%x) " - "loopcount=%d\n", + snd_printdd("ATTENTION! check_reg(%x) loopcount=%d\n", reg, i); return 0; } i++; } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR - "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n", + snd_printk(KERN_ERR "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=0x%x\n", reg, mask, *read); return -EIO; } @@ -161,22 +159,18 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg, #define PCXHR_IT_TEST_XILINX (0x0000003C | PCXHR_MASK_IT_HF1 | \ PCXHR_MASK_IT_MANAGE_HF5) #define PCXHR_IT_DOWNLOAD_BOOT (0x0000000C | PCXHR_MASK_IT_HF1 | \ - PCXHR_MASK_IT_MANAGE_HF5 | \ - PCXHR_MASK_IT_WAIT) + PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT) #define PCXHR_IT_RESET_BOARD_FUNC (0x0000000C | PCXHR_MASK_IT_HF0 | \ - PCXHR_MASK_IT_MANAGE_HF5 | \ - PCXHR_MASK_IT_WAIT_EXTRA) + PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT_EXTRA) #define PCXHR_IT_DOWNLOAD_DSP (0x0000000C | \ - PCXHR_MASK_IT_MANAGE_HF5 | \ - PCXHR_MASK_IT_WAIT) + PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT) #define PCXHR_IT_DEBUG (0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_RESET_SEMAPHORE (0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_MESSAGE (0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_RESET_CHK (0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_UPDATE_RBUFFER (0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1) -static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, - unsigned int itdsp, int atomic) +static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atomic) { int err; unsigned char reg; @@ -184,21 +178,17 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) { /* clear hf5 bit */ PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, - PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & - ~PCXHR_MBOX0_HF5); + PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5); } if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) { - reg = (PCXHR_ICR_HI08_RREQ | - PCXHR_ICR_HI08_TREQ | - PCXHR_ICR_HI08_HDRQ); + reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ; if (itdsp & PCXHR_MASK_IT_HF0) reg |= PCXHR_ICR_HI08_HF0; if (itdsp & PCXHR_MASK_IT_HF1) reg |= PCXHR_ICR_HI08_HF1; PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); } - reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | - PCXHR_CVR_HI08_HC); + reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | PCXHR_CVR_HI08_HC); PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg); if (itdsp & PCXHR_MASK_IT_WAIT) { if (atomic) @@ -221,14 +211,10 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, } if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) { /* wait for hf5 bit */ - err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, - PCXHR_MBOX0_HF5, - PCXHR_MBOX0_HF5, - PCXHR_TIMEOUT_DSP, - ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5, + PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR - "pcxhr_send_it_dsp : TIMEOUT HF5\n"); + snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT HF5\n"); return err; } } @@ -277,8 +263,7 @@ void pcxhr_enable_dsp(struct pcxhr_mgr *mgr) /* * load the xilinx image */ -int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, - const struct firmware *xilinx, int second) +int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilinx, int second) { unsigned int i; unsigned int chipsc; @@ -289,9 +274,7 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, /* test first xilinx */ chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC); /* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */ - /* this bit will always be 1; - * no possibility to test presence of first xilinx - */ + /* this bit will always be 1; no possibility to test presence of first xilinx */ if(second) { if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) { snd_printk(KERN_ERR "error loading first xilinx\n"); @@ -307,8 +290,7 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, data = *image; mask = 0x80; while (mask) { - chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | - PCXHR_CHIPSC_DATA_IN); + chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN); if (data & mask) chipsc |= PCXHR_CHIPSC_DATA_IN; PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc); @@ -348,20 +330,15 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp) data = dsp->data + i; if (i == 0) { /* test data header consistency */ - len = (unsigned int)((data[0]<<16) + - (data[1]<<8) + - data[2]); - if (len && (dsp->size != (len + 2) * 3)) + len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]); + if (len && dsp->size != (len + 2) * 3) return -EINVAL; } /* wait DSP ready for new transfer */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, - PCXHR_ISR_HI08_TRDY, - PCXHR_ISR_HI08_TRDY, - PCXHR_TIMEOUT_DSP, &dummy); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, + PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy); if (err) { - snd_printk(KERN_ERR - "dsp loading error at position %d\n", i); + snd_printk(KERN_ERR "dsp loading error at position %d\n", i); return err; } /* send host data */ @@ -380,8 +357,7 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp) /* * load the eeprom image */ -int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, - const struct firmware *eeprom) +int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eeprom) { int err; unsigned char reg; @@ -389,9 +365,7 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, /* init value of the ICR register */ reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ; if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) { - /* no need to load the eeprom binary, - * but init the HI08 interface - */ + /* no need to load the eeprom binary, but init the HI08 interface */ PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT); msleep(PCXHR_WAIT_DEFAULT); PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); @@ -455,10 +429,8 @@ int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp) if (err) return err; /* wait for chk bit */ - return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, - PCXHR_ISR_HI08_CHK, - PCXHR_ISR_HI08_CHK, - PCXHR_TIMEOUT_DSP, &dummy); + return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, + PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &dummy); } @@ -471,8 +443,8 @@ struct pcxhr_cmd_info { /* RMH status type */ enum { RMH_SSIZE_FIXED = 0, /* status size fix (st_length = 0..x) */ - RMH_SSIZE_ARG = 1, /* status size given in the LSB byte */ - RMH_SSIZE_MASK = 2, /* status size given in bitmask */ + RMH_SSIZE_ARG = 1, /* status size given in the LSB byte (used with st_length = 1) */ + RMH_SSIZE_MASK = 2, /* status size given in bitmask (used with st_length = 1) */ }; /* @@ -502,7 +474,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = { [CMD_UPDATE_R_BUFFERS] = { 0x840000, 0, RMH_SSIZE_FIXED }, [CMD_FORMAT_STREAM_OUT] = { 0x860000, 0, RMH_SSIZE_FIXED }, [CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED }, -[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, +[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, /* stat_len = nb_streams * 2 */ [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, }; @@ -552,13 +524,10 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) for (i = 0; i < rmh->stat_len; i++) { /* wait for receiver full */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, - PCXHR_ISR_HI08_RXDF, - PCXHR_ISR_HI08_RXDF, - PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, + PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR "ERROR RMH stat: " - "ISR:RXDF=1 (ISR = %x; i=%d )\n", + snd_printk(KERN_ERR "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n", reg, i); return err; } @@ -568,10 +537,10 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); /* need to update rmh->stat_len on the fly ?? */ - if (!i) { + if (i==0) { if (rmh->dsp_stat != RMH_SSIZE_FIXED) { if (rmh->dsp_stat == RMH_SSIZE_ARG) { - rmh->stat_len = (data & 0x0000ff) + 1; + rmh->stat_len = (u16)(data & 0x0000ff) + 1; data &= 0xffff00; } else { /* rmh->dsp_stat == RMH_SSIZE_MASK */ @@ -593,8 +562,7 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) rmh->stat[i] = data; } if (rmh->stat_len > max_stat_len) { - snd_printdd("PCXHR : rmh->stat_len=%x too big\n", - rmh->stat_len); + snd_printdd("PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len); rmh->stat_len = max_stat_len; } return 0; @@ -637,8 +605,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ #ifdef CONFIG_SND_DEBUG_VERBOSE if (rmh->cmd_idx < CMD_LAST_INDEX) - snd_printdd("MSG cmd[0]=%x (%s)\n", - data, cmd_names[rmh->cmd_idx]); + snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); #endif err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, @@ -652,10 +619,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) if (rmh->cmd_len > 1) { /* send length */ data = rmh->cmd_len - 1; - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, - PCXHR_ISR_HI08_TRDY, - PCXHR_ISR_HI08_TRDY, - PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, + PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, ®); if (err) return err; PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF); @@ -688,10 +653,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) /* test status ISR */ if (reg & PCXHR_ISR_HI08_ERR) { /* ERROR, wait for receiver full */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, - PCXHR_ISR_HI08_RXDF, - PCXHR_ISR_HI08_RXDF, - PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, + PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); if (err) { snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg); return err; @@ -700,8 +663,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); - snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", - rmh->cmd_idx, data); + snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data); err = -EINVAL; } else { /* read the response data */ @@ -770,9 +732,8 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) { int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2); - /* least segnificant 12 bits are the pipe states - * for the playback audios - * next 12 bits are the pipe states for the capture audios + /* least segnificant 12 bits are the pipe states for the playback audios */ + /* next 12 bits are the pipe states for the capture audios * (PCXHR_PIPE_STATE_CAPTURE_OFFSET) */ start_mask &= 0xffffff; @@ -783,8 +744,7 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) #define PCXHR_PIPE_STATE_CAPTURE_OFFSET 12 #define MAX_WAIT_FOR_DSP 20 -static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, - int audio_mask, int *retry) +static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *retry) { struct pcxhr_rmh rmh; int err; @@ -800,20 +760,17 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, } else { /* can start capture pipe */ pcxhr_set_pipe_cmd_params(&rmh, 1, audio - - PCXHR_PIPE_STATE_CAPTURE_OFFSET, - 0, 0); + PCXHR_PIPE_STATE_CAPTURE_OFFSET, + 0, 0); } err = pcxhr_send_msg(mgr, &rmh); if (err) { snd_printk(KERN_ERR - "error pipe start " - "(CMD_CAN_START_PIPE) err=%x!\n", + "error pipe start (CMD_CAN_START_PIPE) err=%x!\n", err); return err; } - /* if the pipe couldn't be prepaired for start, - * retry it later - */ + /* if the pipe couldn't be prepaired for start, retry it later */ if (rmh.stat[0] == 0) *retry |= (1<<audio); } @@ -838,14 +795,14 @@ static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask) } else { /* stop capture pipe */ pcxhr_set_pipe_cmd_params(&rmh, 1, audio - - PCXHR_PIPE_STATE_CAPTURE_OFFSET, - 0, 0); + PCXHR_PIPE_STATE_CAPTURE_OFFSET, + 0, 0); } err = pcxhr_send_msg(mgr, &rmh); if (err) { snd_printk(KERN_ERR - "error pipe stop " - "(CMD_STOP_PIPE) err=%x!\n", err); + "error pipe stop (CMD_STOP_PIPE) err=%x!\n", + err); return err; } } @@ -865,16 +822,15 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask) if (audio_mask & 1) { pcxhr_init_rmh(&rmh, CMD_CONF_PIPE); if (audio < PCXHR_PIPE_STATE_CAPTURE_OFFSET) - pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0, - 1 << audio); + pcxhr_set_pipe_cmd_params(&rmh, 0, 0, 0, 1 << audio); else pcxhr_set_pipe_cmd_params(&rmh, 1, 0, 0, 1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET)); err = pcxhr_send_msg(mgr, &rmh); if (err) { snd_printk(KERN_ERR - "error pipe start " - "(CMD_CONF_PIPE) err=%x!\n", err); + "error pipe start (CMD_CONF_PIPE) err=%x!\n", + err); return err; } } @@ -885,9 +841,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask) pcxhr_init_rmh(&rmh, CMD_SEND_IRQA); err = pcxhr_send_msg(mgr, &rmh); if (err) { - snd_printk(KERN_ERR - "error pipe start (CMD_SEND_IRQA) err=%x!\n", - err); + snd_printk(KERN_ERR "error pipe start (CMD_SEND_IRQA) err=%x!\n", err ); return err; } return 0; @@ -895,8 +849,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask) -int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, - int capture_mask, int start) +int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_mask, int start) { int state, i, err; int audio_mask; @@ -905,23 +858,21 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, struct timeval my_tv1, my_tv2; do_gettimeofday(&my_tv1); #endif - audio_mask = (playback_mask | - (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET)); + audio_mask = (playback_mask | (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET)); /* current pipe state (playback + record) */ state = pcxhr_pipes_running(mgr); snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n", start ? "START" : "STOP", audio_mask, state); if (start) { - /* start only pipes that are not yet started */ - audio_mask &= ~state; + audio_mask &= ~state; /* start only pipes that are not yet started */ state = audio_mask; for (i = 0; i < MAX_WAIT_FOR_DSP; i++) { err = pcxhr_prepair_pipe_start(mgr, state, &state); if (err) return err; if (state == 0) - break; /* success, all pipes prepaired */ - mdelay(1); /* wait 1 millisecond and retry */ + break; /* success, all pipes prepaired for start */ + mdelay(1); /* otherwise wait 1 millisecond and retry */ } } else { audio_mask &= state; /* stop only pipes that are started */ @@ -940,7 +891,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, if ((state & audio_mask) == (start ? audio_mask : 0)) break; if (++i >= MAX_WAIT_FOR_DSP * 100) { - snd_printk(KERN_ERR "error pipe start/stop\n"); + snd_printk(KERN_ERR "error pipe start/stop (ED_NO_RESPONSE_AT_IRQA)\n"); return -EBUSY; } udelay(10); /* wait 10 microseconds */ @@ -967,8 +918,7 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, spin_lock_irqsave(&mgr->msg_lock, flags); if ((mgr->io_num_reg_cont & mask) == value) { - snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", - mask, value); + snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value); if (changed) *changed = 0; spin_unlock_irqrestore(&mgr->msg_lock, flags); @@ -1021,8 +971,7 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, err = ((err >> 12) & 0xfff); if (!err) return 0; - snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", - err_src_name[err_src], + snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", err_src_name[err_src], is_capture ? "Record" : "Play", pipe, err); if (err == 0xe01) mgr->async_err_stream_xrun++; @@ -1047,13 +996,6 @@ void pcxhr_msg_tasklet(unsigned long arg) snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occured\n"); if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occured\n"); - if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { - /* clear events FREQ_CHANGE and TIME_CODE */ - pcxhr_init_rmh(prmh, CMD_TEST_IT); - err = pcxhr_send_msg(mgr, prmh); - snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n", - err, prmh->stat[0]); - } if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occured\n"); @@ -1063,22 +1005,18 @@ void pcxhr_msg_tasklet(unsigned long arg) prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS; err = pcxhr_send_msg(mgr, prmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", - err); + snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", err); i = 1; while (i < prmh->stat_len) { - int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) & - MASK_FIRST_FIELD); - int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) & - MASK_FIRST_FIELD); + int nb_audio = (prmh->stat[i] >> FIELD_SIZE) & MASK_FIRST_FIELD; + int nb_stream = (prmh->stat[i] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD; int pipe = prmh->stat[i] & MASK_FIRST_FIELD; int is_capture = prmh->stat[i] & 0x400000; u32 err2; if (prmh->stat[i] & 0x800000) { /* if BIT_END */ snd_printdd("TASKLET : End%sPipe %d\n", - is_capture ? "Record" : "Play", - pipe); + is_capture ? "Record" : "Play", pipe); } i++; err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1]; @@ -1124,7 +1062,7 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr, pcxhr_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT); pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture, stream->pipe->first_audio, 0, stream_mask); - /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */ + /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */ err = pcxhr_send_msg(mgr, &rmh); if (err) @@ -1134,21 +1072,18 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr, hw_sample_count += (u_int64_t)rmh.stat[1]; snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n", - stream->pipe->is_capture ? 'C' : 'P', - stream->substream->number, + stream->pipe->is_capture ? 'C':'P', stream->substream->number, (long unsigned int)hw_sample_count, (long unsigned int)(stream->timer_abs_periods + - stream->timer_period_frag + - mgr->granularity)); + stream->timer_period_frag + PCXHR_GRANULARITY)); + return hw_sample_count; } static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, - struct pcxhr_stream *stream, - int samples_to_add) + struct pcxhr_stream *stream, int samples_to_add) { - if (stream->substream && - (stream->status == PCXHR_STREAM_STATUS_RUNNING)) { + if (stream->substream && (stream->status == PCXHR_STREAM_STATUS_RUNNING)) { u_int64_t new_sample_count; int elapsed = 0; int hardware_read = 0; @@ -1157,22 +1092,20 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, if (samples_to_add < 0) { stream->timer_is_synced = 0; /* add default if no hardware_read possible */ - samples_to_add = mgr->granularity; + samples_to_add = PCXHR_GRANULARITY; } if (!stream->timer_is_synced) { - if ((stream->timer_abs_periods != 0) || - ((stream->timer_period_frag + samples_to_add) >= - runtime->period_size)) { - new_sample_count = - pcxhr_stream_read_position(mgr, stream); + if (stream->timer_abs_periods != 0 || + stream->timer_period_frag + PCXHR_GRANULARITY >= + runtime->period_size) { + new_sample_count = pcxhr_stream_read_position(mgr, stream); hardware_read = 1; - if (new_sample_count >= mgr->granularity) { - /* sub security offset because of - * jitter and finer granularity of - * dsp time (MBOX4) + if (new_sample_count >= PCXHR_GRANULARITY_MIN) { + /* sub security offset because of jitter and + * finer granularity of dsp time (MBOX4) */ - new_sample_count -= mgr->granularity; + new_sample_count -= PCXHR_GRANULARITY_MIN; stream->timer_is_synced = 1; } } @@ -1195,15 +1128,12 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, stream->timer_buf_periods = 0; stream->timer_abs_periods = new_elapse_pos; } - if (new_sample_count >= stream->timer_abs_periods) { - stream->timer_period_frag = - (u_int32_t)(new_sample_count - - stream->timer_abs_periods); - } else { - snd_printk(KERN_ERR - "ERROR new_sample_count too small ??? %ld\n", + if (new_sample_count >= stream->timer_abs_periods) + stream->timer_period_frag = (u_int32_t)(new_sample_count - + stream->timer_abs_periods); + else + snd_printk(KERN_ERR "ERROR new_sample_count too small ??? %lx\n", (long unsigned int)new_sample_count); - } if (elapsed) { spin_unlock(&mgr->lock); @@ -1213,6 +1143,7 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, } } + irqreturn_t pcxhr_interrupt(int irq, void *dev_id) { struct pcxhr_mgr *mgr = dev_id; @@ -1225,8 +1156,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS); if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) { spin_unlock(&mgr->lock); - /* this device did not cause the interrupt */ - return IRQ_NONE; + return IRQ_NONE; /* this device did not cause the interrupt */ } /* clear interrupt */ @@ -1237,12 +1167,10 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) if (reg & PCXHR_IRQ_TIMER) { int timer_toggle = reg & PCXHR_IRQ_TIMER; /* is a 24 bit counter */ - int dsp_time_new = - PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; + int dsp_time_new = PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; int dsp_time_diff = dsp_time_new - mgr->dsp_time_last; - if ((dsp_time_diff < 0) && - (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) { + if (dsp_time_diff < 0 && mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID) { snd_printdd("ERROR DSP TIME old(%d) new(%d) -> " "resynchronize all streams\n", mgr->dsp_time_last, dsp_time_new); @@ -1250,49 +1178,40 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) } #ifdef CONFIG_SND_DEBUG_VERBOSE if (dsp_time_diff == 0) - snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", - dsp_time_new); - else if (dsp_time_diff >= (2*mgr->granularity)) + snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); + else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n", - mgr->dsp_time_last, - dsp_time_new - mgr->dsp_time_last); - else if (dsp_time_diff % mgr->granularity) - snd_printdd("ERROR DSP TIME increased by %d\n", - dsp_time_diff); + mgr->dsp_time_last, dsp_time_new - mgr->dsp_time_last); #endif mgr->dsp_time_last = dsp_time_new; - if (timer_toggle == mgr->timer_toggle) { + if (timer_toggle == mgr->timer_toggle) snd_printdd("ERROR TIMER TOGGLE\n"); - mgr->dsp_time_err++; - } mgr->timer_toggle = timer_toggle; reg &= ~PCXHR_IRQ_TIMER; for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; for (j = 0; j < chip->nb_streams_capt; j++) - pcxhr_update_timer_pos(mgr, - &chip->capture_stream[j], - dsp_time_diff); + pcxhr_update_timer_pos(mgr, &chip->capture_stream[j], + dsp_time_diff); } for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; for (j = 0; j < chip->nb_streams_play; j++) - pcxhr_update_timer_pos(mgr, - &chip->playback_stream[j], - dsp_time_diff); + pcxhr_update_timer_pos(mgr, &chip->playback_stream[j], + dsp_time_diff); } } /* other irq's handled in the tasklet */ if (reg & PCXHR_IRQ_MASK) { - if (reg & PCXHR_IRQ_ASYNC) { - /* as we didn't request any async notifications, - * some kind of xrun error will probably occured - */ - /* better resynchronize all streams next interrupt : */ - mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; - } + + /* as we didn't request any notifications, some kind of xrun error + * will probably occured + */ + /* better resynchronize all streams next interrupt : */ + mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; + mgr->src_it_dsp = reg; tasklet_hi_schedule(&mgr->msg_taskq); } diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h index bbbd66d13a64..d9a4ab609875 100644 --- a/sound/pci/pcxhr/pcxhr_core.h +++ b/sound/pci/pcxhr/pcxhr_core.h @@ -65,7 +65,7 @@ enum { CMD_RESYNC_AUDIO_INPUTS, /* cmd_len = 1 stat_len = 0 */ CMD_GET_DSP_RESOURCES, /* cmd_len = 1 stat_len = 4 */ CMD_SET_TIMER_INTERRUPT, /* cmd_len = 1 stat_len = 0 */ - CMD_RES_PIPE, /* cmd_len >=2 stat_len = 0 */ + CMD_RES_PIPE, /* cmd_len = 2 stat_len = 0 */ CMD_FREE_PIPE, /* cmd_len = 1 stat_len = 0 */ CMD_CONF_PIPE, /* cmd_len = 2 stat_len = 0 */ CMD_STOP_PIPE, /* cmd_len = 1 stat_len = 0 */ @@ -96,8 +96,6 @@ void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd); void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh* rmh, int capture, unsigned int param1, unsigned int param2, unsigned int param3); -#define DSP_EXT_CMD_SET(x) (x->dsp_version > 0x012800) - /* send the rmh */ @@ -112,7 +110,6 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh); #define IO_NUM_REG_STATUS 5 #define IO_NUM_REG_CUER 10 #define IO_NUM_UER_CHIP_REG 11 -#define IO_NUM_REG_CONFIG_SRC 12 #define IO_NUM_REG_OUT_ANA_LEVEL 20 #define IO_NUM_REG_IN_ANA_LEVEL 21 diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index 592743a298b0..96640d9c227d 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -31,7 +31,6 @@ #include "pcxhr_mixer.h" #include "pcxhr_hwdep.h" #include "pcxhr_core.h" -#include "pcxhr_mix22.h" #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) @@ -41,10 +40,10 @@ #endif -static int pcxhr_sub_init(struct pcxhr_mgr *mgr); /* * get basic information and init pcxhr card */ + static int pcxhr_init_board(struct pcxhr_mgr *mgr) { int err; @@ -69,7 +68,7 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2) return -EINVAL; /* test 8 or 2 phys in */ - if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) < + if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) != mgr->capture_chips * 2) return -EINVAL; /* test max nb substream per board */ @@ -78,34 +77,20 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) /* test max nb substream per pipe */ if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS) return -EINVAL; - snd_printdd("supported formats : playback=%x capture=%x\n", - rmh.stat[2], rmh.stat[3]); pcxhr_init_rmh(&rmh, CMD_VERSION); /* firmware num for DSP */ rmh.cmd[0] |= mgr->firmware_num; /* transfer granularity in samples (should be multiple of 48) */ - rmh.cmd[1] = (1<<23) + mgr->granularity; + rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY; rmh.cmd_len = 2; err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff, - (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); + snd_printdd("PCXHR DSP version is %d.%d.%d\n", + (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); mgr->dsp_version = rmh.stat[0]; - if (mgr->is_hr_stereo) - err = hr222_sub_init(mgr); - else - err = pcxhr_sub_init(mgr); - return err; -} - -static int pcxhr_sub_init(struct pcxhr_mgr *mgr) -{ - int err; - struct pcxhr_rmh rmh; - /* get options */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_REG_STATUS; @@ -115,22 +100,20 @@ static int pcxhr_sub_init(struct pcxhr_mgr *mgr) if (err) return err; - if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == - REG_STATUS_OPT_ANALOG_BOARD) - mgr->board_has_analog = 1; /* analog addon board found */ + if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD) + mgr->board_has_analog = 1; /* analog addon board available */ + else + /* analog addon board not available -> no support for instance */ + return -EINVAL; /* unmute inputs */ err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, REG_CONT_UNMUTE_INPUTS, NULL); if (err) return err; - /* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */ - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); + /* unmute outputs */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; - if (DSP_EXT_CMD_SET(mgr)) { - rmh.cmd[1] = 1; /* unmute digital plugs */ - rmh.cmd_len = 2; - } err = pcxhr_send_msg(mgr, &rmh); return err; } @@ -141,25 +124,19 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr) if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { /* mute outputs */ - if (!mgr->is_hr_stereo) { /* a read to IO_NUM_REG_MUTE_OUT register unmutes! */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; pcxhr_send_msg(mgr, &rmh); /* mute inputs */ - pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, - 0, NULL); - } - /* stereo cards mute with reset of dsp */ + pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL); } /* reset pcxhr dsp */ - if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) + if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) pcxhr_reset_dsp(mgr); /* reset second xilinx */ - if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) { + if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) pcxhr_reset_xilinx_com(mgr); - mgr->dsp_loaded = 1; - } return; } @@ -167,9 +144,8 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr) /* * allocate a playback/capture pipe (pcmp0/pcmc0) */ -static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr, - struct pcxhr_pipe *pipe, - int is_capture, int pin) +static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe, + int is_capture, int pin) { int stream_count, audio_count; int err; @@ -185,23 +161,15 @@ static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr, stream_count = PCXHR_PLAYBACK_STREAMS; audio_count = 2; /* always stereo */ } - snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", - pin, is_capture ? 'c' : 'p'); + snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p'); pipe->is_capture = is_capture; pipe->first_audio = pin; /* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */ pcxhr_init_rmh(&rmh, CMD_RES_PIPE); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, - audio_count, stream_count); - rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */ - if (DSP_EXT_CMD_SET(mgr)) { - /* add channel mask to command */ - rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03; - } + pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count); err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { - snd_printk(KERN_ERR "error pipe allocation " - "(CMD_RES_PIPE) err=%x!\n", err); + snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err ); return err; } pipe->status = PCXHR_PIPE_DEFINED; @@ -231,12 +199,10 @@ static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe) snd_printk(KERN_ERR "error stopping pipe!\n"); /* release the pipe */ pcxhr_init_rmh(&rmh, CMD_FREE_PIPE); - pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, - 0, 0); + pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0); err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pipe release " - "(CMD_FREE_PIPE) err(%x)\n", err); + snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err); pipe->status = PCXHR_PIPE_UNDEFINED; return err; } @@ -282,16 +248,15 @@ static int pcxhr_start_pipes(struct pcxhr_mgr *mgr) for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; if (chip->nb_streams_play) - playback_mask |= 1 << chip->playback_pipe.first_audio; + playback_mask |= (1 << chip->playback_pipe.first_audio); for (j = 0; j < chip->nb_streams_capt; j++) - capture_mask |= 1 << chip->capture_pipe[j].first_audio; + capture_mask |= (1 << chip->capture_pipe[j].first_audio); } return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); } -static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, - const struct firmware *dsp) +static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmware *dsp) { int err, card_index; @@ -365,33 +330,22 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { - static char *fw_files[][5] = { - [0] = { "xlxint.dat", "xlxc882hr.dat", - "dspe882.e56", "dspb882hr.b56", "dspd882.d56" }, - [1] = { "xlxint.dat", "xlxc882e.dat", - "dspe882.e56", "dspb882e.b56", "dspd882.d56" }, - [2] = { "xlxint.dat", "xlxc1222hr.dat", - "dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" }, - [3] = { "xlxint.dat", "xlxc1222e.dat", - "dspe882.e56", "dspb1222e.b56", "dspd1222.d56" }, - [4] = { NULL, "xlxc222.dat", - "dspe924.e56", "dspb924.b56", "dspd222.d56" }, - [5] = { NULL, "xlxc924.dat", - "dspe924.e56", "dspb924.b56", "dspd222.d56" }, + static char *fw_files[5] = { + "xi_1_882.dat", + "xc_1_882.dat", + "e321_512.e56", + "b321_512.b56", + "d321_512.d56" }; char path[32]; const struct firmware *fw_entry; int i, err; - int fw_set = mgr->fw_file_set; - for (i = 0; i < 5; i++) { - if (!fw_files[fw_set][i]) - continue; - sprintf(path, "pcxhr/%s", fw_files[fw_set][i]); + for (i = 0; i < ARRAY_SIZE(fw_files); i++) { + sprintf(path, "pcxhr/%s", fw_files[i]); if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { - snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", - path); + snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", path); return -ENOENT; } /* fake hwdep dsp record */ @@ -404,26 +358,11 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) return 0; } -MODULE_FIRMWARE("pcxhr/xlxint.dat"); -MODULE_FIRMWARE("pcxhr/xlxc882hr.dat"); -MODULE_FIRMWARE("pcxhr/xlxc882e.dat"); -MODULE_FIRMWARE("pcxhr/dspe882.e56"); -MODULE_FIRMWARE("pcxhr/dspb882hr.b56"); -MODULE_FIRMWARE("pcxhr/dspb882e.b56"); -MODULE_FIRMWARE("pcxhr/dspd882.d56"); - -MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat"); -MODULE_FIRMWARE("pcxhr/xlxc1222e.dat"); -MODULE_FIRMWARE("pcxhr/dspb1222hr.b56"); -MODULE_FIRMWARE("pcxhr/dspb1222e.b56"); -MODULE_FIRMWARE("pcxhr/dspd1222.d56"); - -MODULE_FIRMWARE("pcxhr/xlxc222.dat"); -MODULE_FIRMWARE("pcxhr/xlxc924.dat"); -MODULE_FIRMWARE("pcxhr/dspe924.e56"); -MODULE_FIRMWARE("pcxhr/dspb924.b56"); -MODULE_FIRMWARE("pcxhr/dspd222.d56"); - +MODULE_FIRMWARE("pcxhr/xi_1_882.dat"); +MODULE_FIRMWARE("pcxhr/xc_1_882.dat"); +MODULE_FIRMWARE("pcxhr/e321_512.e56"); +MODULE_FIRMWARE("pcxhr/b321_512.b56"); +MODULE_FIRMWARE("pcxhr/d321_512.d56"); #else /* old style firmware loading */ @@ -434,8 +373,7 @@ MODULE_FIRMWARE("pcxhr/dspd222.d56"); static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw, struct snd_hwdep_dsp_status *info) { - struct pcxhr_mgr *mgr = hw->private_data; - sprintf(info->id, "pcxhr%d", mgr->fw_file_set); + strcpy(info->id, "pcxhr"); info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX; if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) @@ -455,8 +393,8 @@ static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw, fw.size = dsp->length; fw.data = vmalloc(fw.size); if (! fw.data) { - snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image " - "(%lu bytes)\n", (unsigned long)fw.size); + snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image (%lu bytes)\n", + (unsigned long)fw.size); return -ENOMEM; } if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) { @@ -486,11 +424,8 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) int err; struct snd_hwdep *hw; - /* only create hwdep interface for first cardX - * (see "index" module parameter) - */ - err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw); - if (err < 0) + /* only create hwdep interface for first cardX (see "index" module parameter)*/ + if ((err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw)) < 0) return err; hw->iface = SNDRV_HWDEP_IFACE_PCXHR; @@ -500,13 +435,10 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) hw->ops.dsp_status = pcxhr_hwdep_dsp_status; hw->ops.dsp_load = pcxhr_hwdep_dsp_load; hw->exclusive = 1; - /* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */ - hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0; mgr->dsp_loaded = 0; sprintf(hw->name, PCXHR_HWDEP_ID); - err = snd_card_register(mgr->chip[0]->card); - if (err < 0) + if ((err = snd_card_register(mgr->chip[0]->card)) < 0) return err; return 0; } diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c deleted file mode 100644 index ff019126b672..000000000000 --- a/sound/pci/pcxhr/pcxhr_mix22.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Driver for Digigram pcxhr compatible soundcards - * - * mixer interface for stereo cards - * - * Copyright (c) 2004 by Digigram <alsa@digigram.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/delay.h> -#include <linux/io.h> -#include <sound/core.h> -#include <sound/control.h> -#include <sound/tlv.h> -#include <sound/asoundef.h> -#include "pcxhr.h" -#include "pcxhr_core.h" -#include "pcxhr_mix22.h" - - -/* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */ -#define PCXHR_DSP_RESET 0x20 -#define PCXHR_XLX_CFG 0x24 -#define PCXHR_XLX_RUER 0x28 -#define PCXHR_XLX_DATA 0x2C -#define PCXHR_XLX_STATUS 0x30 -#define PCXHR_XLX_LOFREQ 0x34 -#define PCXHR_XLX_HIFREQ 0x38 -#define PCXHR_XLX_CSUER 0x3C -#define PCXHR_XLX_SELMIC 0x40 - -#define PCXHR_DSP 2 - -/* byte access only ! */ -#define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x)) -#define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x)) - - -/* values for PCHR_DSP_RESET register */ -#define PCXHR_DSP_RESET_DSP 0x01 -#define PCXHR_DSP_RESET_MUTE 0x02 -#define PCXHR_DSP_RESET_CODEC 0x08 - -/* values for PCHR_XLX_CFG register */ -#define PCXHR_CFG_SYNCDSP_MASK 0x80 -#define PCXHR_CFG_DEPENDENCY_MASK 0x60 -#define PCXHR_CFG_INDEPENDANT_SEL 0x00 -#define PCXHR_CFG_MASTER_SEL 0x40 -#define PCXHR_CFG_SLAVE_SEL 0x20 -#define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10 /* 0 (UER0), 1(UER1) */ -#define PCXHR_CFG_DATAIN_SEL_MASK 0x08 /* 0 (ana), 1 (UER) */ -#define PCXHR_CFG_SRC_MASK 0x04 /* 0 (Bypass), 1 (SRC Actif) */ -#define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02 /* 0 (UER0), 1(UER1) */ -#define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01 /* 0 (internal), 1 (AES/EBU) */ - -/* values for PCHR_XLX_DATA register */ -#define PCXHR_DATA_CODEC 0x80 -#define AKM_POWER_CONTROL_CMD 0xA007 -#define AKM_RESET_ON_CMD 0xA100 -#define AKM_RESET_OFF_CMD 0xA103 -#define AKM_CLOCK_INF_55K_CMD 0xA240 -#define AKM_CLOCK_SUP_55K_CMD 0xA24D -#define AKM_MUTE_CMD 0xA38D -#define AKM_UNMUTE_CMD 0xA30D -#define AKM_LEFT_LEVEL_CMD 0xA600 -#define AKM_RIGHT_LEVEL_CMD 0xA700 - -/* values for PCHR_XLX_STATUS register - READ */ -#define PCXHR_STAT_SRC_LOCK 0x01 -#define PCXHR_STAT_LEVEL_IN 0x02 -#define PCXHR_STAT_MIC_CAPS 0x10 -/* values for PCHR_XLX_STATUS register - WRITE */ -#define PCXHR_STAT_FREQ_SYNC_MASK 0x01 -#define PCXHR_STAT_FREQ_UER1_MASK 0x02 -#define PCXHR_STAT_FREQ_SAVE_MASK 0x80 - -/* values for PCHR_XLX_CSUER register */ -#define PCXHR_SUER1_BIT_U_READ_MASK 0x80 -#define PCXHR_SUER1_BIT_C_READ_MASK 0x40 -#define PCXHR_SUER1_DATA_PRESENT_MASK 0x20 -#define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10 -#define PCXHR_SUER_BIT_U_READ_MASK 0x08 -#define PCXHR_SUER_BIT_C_READ_MASK 0x04 -#define PCXHR_SUER_DATA_PRESENT_MASK 0x02 -#define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01 - -#define PCXHR_SUER_BIT_U_WRITE_MASK 0x02 -#define PCXHR_SUER_BIT_C_WRITE_MASK 0x01 - -/* values for PCXHR_XLX_SELMIC register - WRITE */ -#define PCXHR_SELMIC_PREAMPLI_OFFSET 2 -#define PCXHR_SELMIC_PREAMPLI_MASK 0x0C -#define PCXHR_SELMIC_PHANTOM_ALIM 0x80 - - -static const unsigned char g_hr222_p_level[] = { - 0x00, /* [000] -49.5 dB: AKM[000] = -1.#INF dB (mute) */ - 0x01, /* [001] -49.0 dB: AKM[001] = -48.131 dB (diff=0.86920 dB) */ - 0x01, /* [002] -48.5 dB: AKM[001] = -48.131 dB (diff=0.36920 dB) */ - 0x01, /* [003] -48.0 dB: AKM[001] = -48.131 dB (diff=0.13080 dB) */ - 0x01, /* [004] -47.5 dB: AKM[001] = -48.131 dB (diff=0.63080 dB) */ - 0x01, /* [005] -46.5 dB: AKM[001] = -48.131 dB (diff=1.63080 dB) */ - 0x01, /* [006] -47.0 dB: AKM[001] = -48.131 dB (diff=1.13080 dB) */ - 0x01, /* [007] -46.0 dB: AKM[001] = -48.131 dB (diff=2.13080 dB) */ - 0x01, /* [008] -45.5 dB: AKM[001] = -48.131 dB (diff=2.63080 dB) */ - 0x02, /* [009] -45.0 dB: AKM[002] = -42.110 dB (diff=2.88980 dB) */ - 0x02, /* [010] -44.5 dB: AKM[002] = -42.110 dB (diff=2.38980 dB) */ - 0x02, /* [011] -44.0 dB: AKM[002] = -42.110 dB (diff=1.88980 dB) */ - 0x02, /* [012] -43.5 dB: AKM[002] = -42.110 dB (diff=1.38980 dB) */ - 0x02, /* [013] -43.0 dB: AKM[002] = -42.110 dB (diff=0.88980 dB) */ - 0x02, /* [014] -42.5 dB: AKM[002] = -42.110 dB (diff=0.38980 dB) */ - 0x02, /* [015] -42.0 dB: AKM[002] = -42.110 dB (diff=0.11020 dB) */ - 0x02, /* [016] -41.5 dB: AKM[002] = -42.110 dB (diff=0.61020 dB) */ - 0x02, /* [017] -41.0 dB: AKM[002] = -42.110 dB (diff=1.11020 dB) */ - 0x02, /* [018] -40.5 dB: AKM[002] = -42.110 dB (diff=1.61020 dB) */ - 0x03, /* [019] -40.0 dB: AKM[003] = -38.588 dB (diff=1.41162 dB) */ - 0x03, /* [020] -39.5 dB: AKM[003] = -38.588 dB (diff=0.91162 dB) */ - 0x03, /* [021] -39.0 dB: AKM[003] = -38.588 dB (diff=0.41162 dB) */ - 0x03, /* [022] -38.5 dB: AKM[003] = -38.588 dB (diff=0.08838 dB) */ - 0x03, /* [023] -38.0 dB: AKM[003] = -38.588 dB (diff=0.58838 dB) */ - 0x03, /* [024] -37.5 dB: AKM[003] = -38.588 dB (diff=1.08838 dB) */ - 0x04, /* [025] -37.0 dB: AKM[004] = -36.090 dB (diff=0.91040 dB) */ - 0x04, /* [026] -36.5 dB: AKM[004] = -36.090 dB (diff=0.41040 dB) */ - 0x04, /* [027] -36.0 dB: AKM[004] = -36.090 dB (diff=0.08960 dB) */ - 0x04, /* [028] -35.5 dB: AKM[004] = -36.090 dB (diff=0.58960 dB) */ - 0x05, /* [029] -35.0 dB: AKM[005] = -34.151 dB (diff=0.84860 dB) */ - 0x05, /* [030] -34.5 dB: AKM[005] = -34.151 dB (diff=0.34860 dB) */ - 0x05, /* [031] -34.0 dB: AKM[005] = -34.151 dB (diff=0.15140 dB) */ - 0x05, /* [032] -33.5 dB: AKM[005] = -34.151 dB (diff=0.65140 dB) */ - 0x06, /* [033] -33.0 dB: AKM[006] = -32.568 dB (diff=0.43222 dB) */ - 0x06, /* [034] -32.5 dB: AKM[006] = -32.568 dB (diff=0.06778 dB) */ - 0x06, /* [035] -32.0 dB: AKM[006] = -32.568 dB (diff=0.56778 dB) */ - 0x07, /* [036] -31.5 dB: AKM[007] = -31.229 dB (diff=0.27116 dB) */ - 0x07, /* [037] -31.0 dB: AKM[007] = -31.229 dB (diff=0.22884 dB) */ - 0x08, /* [038] -30.5 dB: AKM[008] = -30.069 dB (diff=0.43100 dB) */ - 0x08, /* [039] -30.0 dB: AKM[008] = -30.069 dB (diff=0.06900 dB) */ - 0x09, /* [040] -29.5 dB: AKM[009] = -29.046 dB (diff=0.45405 dB) */ - 0x09, /* [041] -29.0 dB: AKM[009] = -29.046 dB (diff=0.04595 dB) */ - 0x0a, /* [042] -28.5 dB: AKM[010] = -28.131 dB (diff=0.36920 dB) */ - 0x0a, /* [043] -28.0 dB: AKM[010] = -28.131 dB (diff=0.13080 dB) */ - 0x0b, /* [044] -27.5 dB: AKM[011] = -27.303 dB (diff=0.19705 dB) */ - 0x0b, /* [045] -27.0 dB: AKM[011] = -27.303 dB (diff=0.30295 dB) */ - 0x0c, /* [046] -26.5 dB: AKM[012] = -26.547 dB (diff=0.04718 dB) */ - 0x0d, /* [047] -26.0 dB: AKM[013] = -25.852 dB (diff=0.14806 dB) */ - 0x0e, /* [048] -25.5 dB: AKM[014] = -25.208 dB (diff=0.29176 dB) */ - 0x0e, /* [049] -25.0 dB: AKM[014] = -25.208 dB (diff=0.20824 dB) */ - 0x0f, /* [050] -24.5 dB: AKM[015] = -24.609 dB (diff=0.10898 dB) */ - 0x10, /* [051] -24.0 dB: AKM[016] = -24.048 dB (diff=0.04840 dB) */ - 0x11, /* [052] -23.5 dB: AKM[017] = -23.522 dB (diff=0.02183 dB) */ - 0x12, /* [053] -23.0 dB: AKM[018] = -23.025 dB (diff=0.02535 dB) */ - 0x13, /* [054] -22.5 dB: AKM[019] = -22.556 dB (diff=0.05573 dB) */ - 0x14, /* [055] -22.0 dB: AKM[020] = -22.110 dB (diff=0.11020 dB) */ - 0x15, /* [056] -21.5 dB: AKM[021] = -21.686 dB (diff=0.18642 dB) */ - 0x17, /* [057] -21.0 dB: AKM[023] = -20.896 dB (diff=0.10375 dB) */ - 0x18, /* [058] -20.5 dB: AKM[024] = -20.527 dB (diff=0.02658 dB) */ - 0x1a, /* [059] -20.0 dB: AKM[026] = -19.831 dB (diff=0.16866 dB) */ - 0x1b, /* [060] -19.5 dB: AKM[027] = -19.504 dB (diff=0.00353 dB) */ - 0x1d, /* [061] -19.0 dB: AKM[029] = -18.883 dB (diff=0.11716 dB) */ - 0x1e, /* [062] -18.5 dB: AKM[030] = -18.588 dB (diff=0.08838 dB) */ - 0x20, /* [063] -18.0 dB: AKM[032] = -18.028 dB (diff=0.02780 dB) */ - 0x22, /* [064] -17.5 dB: AKM[034] = -17.501 dB (diff=0.00123 dB) */ - 0x24, /* [065] -17.0 dB: AKM[036] = -17.005 dB (diff=0.00475 dB) */ - 0x26, /* [066] -16.5 dB: AKM[038] = -16.535 dB (diff=0.03513 dB) */ - 0x28, /* [067] -16.0 dB: AKM[040] = -16.090 dB (diff=0.08960 dB) */ - 0x2b, /* [068] -15.5 dB: AKM[043] = -15.461 dB (diff=0.03857 dB) */ - 0x2d, /* [069] -15.0 dB: AKM[045] = -15.067 dB (diff=0.06655 dB) */ - 0x30, /* [070] -14.5 dB: AKM[048] = -14.506 dB (diff=0.00598 dB) */ - 0x33, /* [071] -14.0 dB: AKM[051] = -13.979 dB (diff=0.02060 dB) */ - 0x36, /* [072] -13.5 dB: AKM[054] = -13.483 dB (diff=0.01707 dB) */ - 0x39, /* [073] -13.0 dB: AKM[057] = -13.013 dB (diff=0.01331 dB) */ - 0x3c, /* [074] -12.5 dB: AKM[060] = -12.568 dB (diff=0.06778 dB) */ - 0x40, /* [075] -12.0 dB: AKM[064] = -12.007 dB (diff=0.00720 dB) */ - 0x44, /* [076] -11.5 dB: AKM[068] = -11.481 dB (diff=0.01937 dB) */ - 0x48, /* [077] -11.0 dB: AKM[072] = -10.984 dB (diff=0.01585 dB) */ - 0x4c, /* [078] -10.5 dB: AKM[076] = -10.515 dB (diff=0.01453 dB) */ - 0x51, /* [079] -10.0 dB: AKM[081] = -9.961 dB (diff=0.03890 dB) */ - 0x55, /* [080] -9.5 dB: AKM[085] = -9.542 dB (diff=0.04243 dB) */ - 0x5a, /* [081] -9.0 dB: AKM[090] = -9.046 dB (diff=0.04595 dB) */ - 0x60, /* [082] -8.5 dB: AKM[096] = -8.485 dB (diff=0.01462 dB) */ - 0x66, /* [083] -8.0 dB: AKM[102] = -7.959 dB (diff=0.04120 dB) */ - 0x6c, /* [084] -7.5 dB: AKM[108] = -7.462 dB (diff=0.03767 dB) */ - 0x72, /* [085] -7.0 dB: AKM[114] = -6.993 dB (diff=0.00729 dB) */ - 0x79, /* [086] -6.5 dB: AKM[121] = -6.475 dB (diff=0.02490 dB) */ - 0x80, /* [087] -6.0 dB: AKM[128] = -5.987 dB (diff=0.01340 dB) */ - 0x87, /* [088] -5.5 dB: AKM[135] = -5.524 dB (diff=0.02413 dB) */ - 0x8f, /* [089] -5.0 dB: AKM[143] = -5.024 dB (diff=0.02408 dB) */ - 0x98, /* [090] -4.5 dB: AKM[152] = -4.494 dB (diff=0.00607 dB) */ - 0xa1, /* [091] -4.0 dB: AKM[161] = -3.994 dB (diff=0.00571 dB) */ - 0xaa, /* [092] -3.5 dB: AKM[170] = -3.522 dB (diff=0.02183 dB) */ - 0xb5, /* [093] -3.0 dB: AKM[181] = -2.977 dB (diff=0.02277 dB) */ - 0xbf, /* [094] -2.5 dB: AKM[191] = -2.510 dB (diff=0.01014 dB) */ - 0xcb, /* [095] -2.0 dB: AKM[203] = -1.981 dB (diff=0.01912 dB) */ - 0xd7, /* [096] -1.5 dB: AKM[215] = -1.482 dB (diff=0.01797 dB) */ - 0xe3, /* [097] -1.0 dB: AKM[227] = -1.010 dB (diff=0.01029 dB) */ - 0xf1, /* [098] -0.5 dB: AKM[241] = -0.490 dB (diff=0.00954 dB) */ - 0xff, /* [099] +0.0 dB: AKM[255] = +0.000 dB (diff=0.00000 dB) */ -}; - - -static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data) -{ - unsigned short mask = 0x8000; - /* activate access to codec registers */ - PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ); - - while (mask) { - PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, - data & mask ? PCXHR_DATA_CODEC : 0); - mask >>= 1; - } - /* termiate access to codec registers */ - PCXHR_INPB(mgr, PCXHR_XLX_RUER); -} - - -static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr, - int idx, int level) -{ - unsigned short cmd; - if (idx > 1 || - level < 0 || - level >= ARRAY_SIZE(g_hr222_p_level)) - return -EINVAL; - - if (idx == 0) - cmd = AKM_LEFT_LEVEL_CMD; - else - cmd = AKM_RIGHT_LEVEL_CMD; - - /* conversion from PmBoardCodedLevel to AKM nonlinear programming */ - cmd += g_hr222_p_level[level]; - - hr222_config_akm(mgr, cmd); - return 0; -} - - -static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr, - int level_l, int level_r, int level_mic) -{ - /* program all input levels at the same time */ - unsigned int data; - int i; - - if (!mgr->capture_chips) - return -EINVAL; /* no PCX22 */ - - data = ((level_mic & 0xff) << 24); /* micro is mono, but apply */ - data |= ((level_mic & 0xff) << 16); /* level on both channels */ - data |= ((level_r & 0xff) << 8); /* line input right channel */ - data |= (level_l & 0xff); /* line input left channel */ - - PCXHR_INPB(mgr, PCXHR_XLX_DATA); /* activate input codec */ - /* send 32 bits (4 x 8 bits) */ - for (i = 0; i < 32; i++, data <<= 1) { - PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, - (data & 0x80000000) ? PCXHR_DATA_CODEC : 0); - } - PCXHR_INPB(mgr, PCXHR_XLX_RUER); /* close input level codec */ - return 0; -} - -static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level); - -int hr222_sub_init(struct pcxhr_mgr *mgr) -{ - unsigned char reg; - - mgr->board_has_analog = 1; /* analog always available */ - mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK; - - reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); - if (reg & PCXHR_STAT_MIC_CAPS) - mgr->board_has_mic = 1; /* microphone available */ - snd_printdd("MIC input available = %d\n", mgr->board_has_mic); - - /* reset codec */ - PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, - PCXHR_DSP_RESET_DSP); - msleep(5); - PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, - PCXHR_DSP_RESET_DSP | - PCXHR_DSP_RESET_MUTE | - PCXHR_DSP_RESET_CODEC); - msleep(5); - - /* config AKM */ - hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD); - hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); - hr222_config_akm(mgr, AKM_UNMUTE_CMD); - hr222_config_akm(mgr, AKM_RESET_OFF_CMD); - - /* init micro boost */ - hr222_micro_boost(mgr, 0); - - return 0; -} - - -/* calc PLL register */ -/* TODO : there is a very similar fct in pcxhr.c */ -static int hr222_pll_freq_register(unsigned int freq, - unsigned int *pllreg, - unsigned int *realfreq) -{ - unsigned int reg; - - if (freq < 6900 || freq > 219000) - return -EINVAL; - reg = (28224000 * 2) / freq; - reg = (reg - 1) / 2; - if (reg < 0x100) - *pllreg = reg + 0xC00; - else if (reg < 0x200) - *pllreg = reg + 0x800; - else if (reg < 0x400) - *pllreg = reg & 0x1ff; - else if (reg < 0x800) { - *pllreg = ((reg >> 1) & 0x1ff) + 0x200; - reg &= ~1; - } else { - *pllreg = ((reg >> 2) & 0x1ff) + 0x400; - reg &= ~3; - } - if (realfreq) - *realfreq = (28224000 / (reg + 1)); - return 0; -} - -int hr222_sub_set_clock(struct pcxhr_mgr *mgr, - unsigned int rate, - int *changed) -{ - unsigned int speed, pllreg = 0; - int err; - unsigned realfreq = rate; - - switch (mgr->use_clock_type) { - case HR22_CLOCK_TYPE_INTERNAL: - err = hr222_pll_freq_register(rate, &pllreg, &realfreq); - if (err) - return err; - - mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK | - PCXHR_CFG_CLOCK_UER1_SEL_MASK); - break; - case HR22_CLOCK_TYPE_AES_SYNC: - mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK; - mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK; - break; - case HR22_CLOCK_TYPE_AES_1: - if (!mgr->board_has_aes1) - return -EINVAL; - - mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK | - PCXHR_CFG_CLOCK_UER1_SEL_MASK); - break; - default: - return -EINVAL; - } - hr222_config_akm(mgr, AKM_MUTE_CMD); - - if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) { - PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8); - PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff); - } - - /* set clock source */ - PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg); - - /* codec speed modes */ - speed = rate < 55000 ? 0 : 1; - if (mgr->codec_speed != speed) { - mgr->codec_speed = speed; - if (speed == 0) - hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); - else - hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD); - } - - mgr->sample_rate_real = realfreq; - mgr->cur_clock_type = mgr->use_clock_type; - - if (changed) - *changed = 1; - - hr222_config_akm(mgr, AKM_UNMUTE_CMD); - - snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n", - rate, realfreq, pllreg); - return 0; -} - -int hr222_get_external_clock(struct pcxhr_mgr *mgr, - enum pcxhr_clock_type clock_type, - int *sample_rate) -{ - int rate, calc_rate = 0; - unsigned int ticks; - unsigned char mask, reg; - - if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) { - - mask = (PCXHR_SUER_CLOCK_PRESENT_MASK | - PCXHR_SUER_DATA_PRESENT_MASK); - reg = PCXHR_STAT_FREQ_SYNC_MASK; - - } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) { - - mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK | - PCXHR_SUER1_DATA_PRESENT_MASK); - reg = PCXHR_STAT_FREQ_UER1_MASK; - - } else { - snd_printdd("get_external_clock : type %d not supported\n", - clock_type); - return -EINVAL; /* other clocks not supported */ - } - - if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) { - snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type); - *sample_rate = 0; - return 0; /* no external clock locked */ - } - - PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */ - - /* save the measured clock frequency */ - reg |= PCXHR_STAT_FREQ_SAVE_MASK; - - if (mgr->last_reg_stat != reg) { - udelay(500); /* wait min 2 cycles of lowest freq (8000) */ - mgr->last_reg_stat = reg; - } - - PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */ - - /* get the frequency */ - ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG); - ticks = (ticks & 0x03) << 8; - ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET); - - if (ticks != 0) - calc_rate = 28224000 / ticks; - /* rounding */ - if (calc_rate > 184200) - rate = 192000; - else if (calc_rate > 152200) - rate = 176400; - else if (calc_rate > 112000) - rate = 128000; - else if (calc_rate > 92100) - rate = 96000; - else if (calc_rate > 76100) - rate = 88200; - else if (calc_rate > 56000) - rate = 64000; - else if (calc_rate > 46050) - rate = 48000; - else if (calc_rate > 38050) - rate = 44100; - else if (calc_rate > 28000) - rate = 32000; - else if (calc_rate > 23025) - rate = 24000; - else if (calc_rate > 19025) - rate = 22050; - else if (calc_rate > 14000) - rate = 16000; - else if (calc_rate > 11512) - rate = 12000; - else if (calc_rate > 9512) - rate = 11025; - else if (calc_rate > 7000) - rate = 8000; - else - rate = 0; - - snd_printdd("External clock is at %d Hz (measured %d Hz)\n", - rate, calc_rate); - *sample_rate = rate; - return 0; -} - - -int hr222_update_analog_audio_level(struct snd_pcxhr *chip, - int is_capture, int channel) -{ - snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n", - is_capture ? "capture" : "playback", channel); - if (is_capture) { - int level_l, level_r, level_mic; - /* we have to update all levels */ - if (chip->analog_capture_active) { - level_l = chip->analog_capture_volume[0]; - level_r = chip->analog_capture_volume[1]; - } else { - level_l = HR222_LINE_CAPTURE_LEVEL_MIN; - level_r = HR222_LINE_CAPTURE_LEVEL_MIN; - } - if (chip->mic_active) - level_mic = chip->mic_volume; - else - level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN; - return hr222_set_hw_capture_level(chip->mgr, - level_l, level_r, level_mic); - } else { - int vol; - if (chip->analog_playback_active[channel]) - vol = chip->analog_playback_volume[channel]; - else - vol = HR222_LINE_PLAYBACK_LEVEL_MIN; - return hr222_set_hw_playback_level(chip->mgr, channel, vol); - } -} - - -/*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/ -#define SOURCE_LINE 0 -#define SOURCE_DIGITAL 1 -#define SOURCE_DIGISRC 2 -#define SOURCE_MIC 3 -#define SOURCE_LINEMIC 4 - -int hr222_set_audio_source(struct snd_pcxhr *chip) -{ - int digital = 0; - /* default analog source */ - chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK | - PCXHR_CFG_DATAIN_SEL_MASK | - PCXHR_CFG_DATA_UER1_SEL_MASK); - - if (chip->audio_capture_source == SOURCE_DIGISRC) { - chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK; - digital = 1; - } else { - if (chip->audio_capture_source == SOURCE_DIGITAL) - digital = 1; - } - if (digital) { - chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK; - if (chip->mgr->board_has_aes1) { - /* get data from the AES1 plug */ - chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK; - } - /* chip->mic_active = 0; */ - /* chip->analog_capture_active = 0; */ - } else { - int update_lvl = 0; - chip->analog_capture_active = 0; - chip->mic_active = 0; - if (chip->audio_capture_source == SOURCE_LINE || - chip->audio_capture_source == SOURCE_LINEMIC) { - if (chip->analog_capture_active == 0) - update_lvl = 1; - chip->analog_capture_active = 1; - } - if (chip->audio_capture_source == SOURCE_MIC || - chip->audio_capture_source == SOURCE_LINEMIC) { - if (chip->mic_active == 0) - update_lvl = 1; - chip->mic_active = 1; - } - if (update_lvl) { - /* capture: update all 3 mutes/unmutes with one call */ - hr222_update_analog_audio_level(chip, 1, 0); - } - } - /* set the source infos (max 3 bits modified) */ - PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg); - return 0; -} - - -int hr222_iec958_capture_byte(struct snd_pcxhr *chip, - int aes_idx, unsigned char *aes_bits) -{ - unsigned char idx = (unsigned char)(aes_idx * 8); - unsigned char temp = 0; - unsigned char mask = chip->mgr->board_has_aes1 ? - PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK; - int i; - for (i = 0; i < 8; i++) { - PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */ - temp <<= 1; - if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask) - temp |= 1; - } - snd_printdd("read iec958 AES %d byte %d = 0x%x\n", - chip->chip_idx, aes_idx, temp); - *aes_bits = temp; - return 0; -} - - -int hr222_iec958_update_byte(struct snd_pcxhr *chip, - int aes_idx, unsigned char aes_bits) -{ - int i; - unsigned char new_bits = aes_bits; - unsigned char old_bits = chip->aes_bits[aes_idx]; - unsigned char idx = (unsigned char)(aes_idx * 8); - for (i = 0; i < 8; i++) { - if ((old_bits & 0x01) != (new_bits & 0x01)) { - /* idx < 192 */ - PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx); - /* write C and U bit */ - PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ? - PCXHR_SUER_BIT_C_WRITE_MASK : 0); - } - idx++; - old_bits >>= 1; - new_bits >>= 1; - } - chip->aes_bits[aes_idx] = aes_bits; - return 0; -} - -static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level) -{ - unsigned char boost_mask; - boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET); - if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK)) - return; /* only values form 0 to 3 accepted */ - - mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK; - mgr->xlx_selmic |= boost_mask; - - PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); - - snd_printdd("hr222_micro_boost : set %x\n", boost_mask); -} - -static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) -{ - if (power) - mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM; - else - mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM; - - PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); - - snd_printdd("hr222_phantom_power : set %d\n", power); -} - - -/* mic level */ -static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650); - -static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */ - /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */ - uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /* +7 dB */ - return 0; -} - -static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); - ucontrol->value.integer.value[0] = chip->mic_volume; - mutex_unlock(&chip->mgr->mixer_mutex); - return 0; -} - -static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int changed = 0; - mutex_lock(&chip->mgr->mixer_mutex); - if (chip->mic_volume != ucontrol->value.integer.value[0]) { - changed = 1; - chip->mic_volume = ucontrol->value.integer.value[0]; - hr222_update_analog_audio_level(chip, 1, 0); - } - mutex_unlock(&chip->mgr->mixer_mutex); - return changed; -} - -static struct snd_kcontrol_new hr222_control_mic_level = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ), - .name = "Mic Capture Volume", - .info = hr222_mic_vol_info, - .get = hr222_mic_vol_get, - .put = hr222_mic_vol_put, - .tlv = { .p = db_scale_mic_hr222 }, -}; - - -/* mic boost level */ -static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400); - -static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; /* 0 dB */ - uinfo->value.integer.max = 3; /* 54 dB */ - return 0; -} - -static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); - ucontrol->value.integer.value[0] = chip->mic_boost; - mutex_unlock(&chip->mgr->mixer_mutex); - return 0; -} - -static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int changed = 0; - mutex_lock(&chip->mgr->mixer_mutex); - if (chip->mic_boost != ucontrol->value.integer.value[0]) { - changed = 1; - chip->mic_boost = ucontrol->value.integer.value[0]; - hr222_micro_boost(chip->mgr, chip->mic_boost); - } - mutex_unlock(&chip->mgr->mixer_mutex); - return changed; -} - -static struct snd_kcontrol_new hr222_control_mic_boost = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ), - .name = "MicBoost Capture Volume", - .info = hr222_mic_boost_info, - .get = hr222_mic_boost_get, - .put = hr222_mic_boost_put, - .tlv = { .p = db_scale_micboost_hr222 }, -}; - - -/******************* Phantom power switch *******************/ -#define hr222_phantom_power_info snd_ctl_boolean_mono_info - -static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - mutex_lock(&chip->mgr->mixer_mutex); - ucontrol->value.integer.value[0] = chip->phantom_power; - mutex_unlock(&chip->mgr->mixer_mutex); - return 0; -} - -static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int power, changed = 0; - - mutex_lock(&chip->mgr->mixer_mutex); - power = !!ucontrol->value.integer.value[0]; - if (chip->phantom_power != power) { - hr222_phantom_power(chip->mgr, power); - chip->phantom_power = power; - changed = 1; - } - mutex_unlock(&chip->mgr->mixer_mutex); - return changed; -} - -static struct snd_kcontrol_new hr222_phantom_power_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Phantom Power Switch", - .info = hr222_phantom_power_info, - .get = hr222_phantom_power_get, - .put = hr222_phantom_power_put, -}; - - -int hr222_add_mic_controls(struct snd_pcxhr *chip) -{ - int err; - if (!chip->mgr->board_has_mic) - return 0; - - /* controls */ - err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level, - chip)); - if (err < 0) - return err; - - err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost, - chip)); - if (err < 0) - return err; - - err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch, - chip)); - return err; -} diff --git a/sound/pci/pcxhr/pcxhr_mix22.h b/sound/pci/pcxhr/pcxhr_mix22.h deleted file mode 100644 index 6b318b2f0100..000000000000 --- a/sound/pci/pcxhr/pcxhr_mix22.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Driver for Digigram pcxhr compatible soundcards - * - * low level interface with interrupt ans message handling - * - * Copyright (c) 2004 by Digigram <alsa@digigram.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __SOUND_PCXHR_MIX22_H -#define __SOUND_PCXHR_MIX22_H - -struct pcxhr_mgr; - -int hr222_sub_init(struct pcxhr_mgr *mgr); -int hr222_sub_set_clock(struct pcxhr_mgr *mgr, unsigned int rate, - int *changed); -int hr222_get_external_clock(struct pcxhr_mgr *mgr, - enum pcxhr_clock_type clock_type, - int *sample_rate); - -#define HR222_LINE_PLAYBACK_LEVEL_MIN 0 /* -25.5 dB */ -#define HR222_LINE_PLAYBACK_ZERO_LEVEL 51 /* 0.0 dB */ -#define HR222_LINE_PLAYBACK_LEVEL_MAX 99 /* +24.0 dB */ - -#define HR222_LINE_CAPTURE_LEVEL_MIN 0 /* -111.5 dB */ -#define HR222_LINE_CAPTURE_ZERO_LEVEL 223 /* 0.0 dB */ -#define HR222_LINE_CAPTURE_LEVEL_MAX 255 /* +16 dB */ -#define HR222_MICRO_CAPTURE_LEVEL_MIN 0 /* -98.5 dB */ -#define HR222_MICRO_CAPTURE_LEVEL_MAX 210 /* +6.5 dB */ - -int hr222_update_analog_audio_level(struct snd_pcxhr *chip, - int is_capture, - int channel); -int hr222_set_audio_source(struct snd_pcxhr *chip); -int hr222_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, - unsigned char *aes_bits); -int hr222_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, - unsigned char aes_bits); - -int hr222_add_mic_controls(struct snd_pcxhr *chip); - -#endif /* __SOUND_PCXHR_MIX22_H */ diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 2436e374586f..aabc7bc5321e 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -33,24 +33,20 @@ #include <sound/tlv.h> #include <sound/asoundef.h> #include "pcxhr_mixer.h" -#include "pcxhr_mix22.h" -#define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */ -#define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */ -#define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */ -#define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */ -#define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */ -#define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */ +#define PCXHR_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB */ +#define PCXHR_ANALOG_CAPTURE_LEVEL_MAX 255 /* +31.5 dB */ +#define PCXHR_ANALOG_CAPTURE_ZERO_LEVEL 224 /* +16.0 dB ( +31.5 dB - fix level +15.5 dB ) */ -static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550); -static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); +#define PCXHR_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -128.0 dB */ +#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ +#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ -static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600); -static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 3150); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); -static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, - int is_capture, int channel) +static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) { int err, vol; struct pcxhr_rmh rmh; @@ -64,17 +60,15 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, if (chip->analog_playback_active[channel]) vol = chip->analog_playback_volume[channel]; else - vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; - /* playback analog levels are inversed */ - rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; + vol = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; + rmh.cmd[2] = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX - vol; /* playback analog levels are inversed */ } rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { - snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)" - " is_capture(%d) err(%x)\n", - chip->chip_idx, is_capture, err); + snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d) " + "is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err); return -EINVAL; } return 0; @@ -86,34 +80,14 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; if (kcontrol->private_value == 0) { /* playback */ - if (chip->mgr->is_hr_stereo) { - uinfo->value.integer.min = - HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */ - uinfo->value.integer.max = - HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ - } else { - uinfo->value.integer.min = - PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */ - uinfo->value.integer.max = - PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ - } + uinfo->value.integer.min = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; /* -128 dB */ + uinfo->value.integer.max = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */ } else { /* capture */ - if (chip->mgr->is_hr_stereo) { - uinfo->value.integer.min = - HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ - uinfo->value.integer.max = - HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ - } else { - uinfo->value.integer.min = - PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ - uinfo->value.integer.max = - PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ - } + uinfo->value.integer.min = PCXHR_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */ + uinfo->value.integer.max = PCXHR_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */ } return 0; } @@ -124,11 +98,11 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); mutex_lock(&chip->mgr->mixer_mutex); if (kcontrol->private_value == 0) { /* playback */ - ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; - ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; + ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; } else { /* capture */ - ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; - ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; + ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; } mutex_unlock(&chip->mgr->mixer_mutex); return 0; @@ -149,35 +123,18 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i]; if (is_capture) { - if (chip->mgr->is_hr_stereo) { - if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN || - new_volume > HR222_LINE_CAPTURE_LEVEL_MAX) - continue; - } else { - if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN || - new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX) - continue; - } + if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN || + new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX) + continue; } else { - if (chip->mgr->is_hr_stereo) { - if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN || - new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX) - continue; - } else { - if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN || - new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX) - continue; - } + if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN || + new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX) + continue; } if (*stored_volume != new_volume) { *stored_volume = new_volume; changed = 1; - if (chip->mgr->is_hr_stereo) - hr222_update_analog_audio_level(chip, - is_capture, i); - else - pcxhr_update_analog_audio_level(chip, - is_capture, i); + pcxhr_update_analog_audio_level(chip, is_capture, i); } } mutex_unlock(&chip->mgr->mixer_mutex); @@ -196,7 +153,6 @@ static struct snd_kcontrol_new pcxhr_control_analog_level = { }; /* shared */ - #define pcxhr_sw_info snd_ctl_boolean_stereo_info static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, @@ -224,10 +180,7 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, !!ucontrol->value.integer.value[i]; changed = 1; /* update playback levels */ - if (chip->mgr->is_hr_stereo) - hr222_update_analog_audio_level(chip, 0, i); - else - pcxhr_update_analog_audio_level(chip, 0, i); + pcxhr_update_analog_audio_level(chip, 0, i); } } mutex_unlock(&chip->mgr->mixer_mutex); @@ -298,8 +251,7 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 -static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, - int capture, int channel) +static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, int channel) { int err; struct pcxhr_rmh rmh; @@ -312,20 +264,18 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); /* add channel mask */ - pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, - 1 << (channel + pipe->first_audio)); - /* TODO : if mask (3 << pipe->first_audio) is used, left and right - * channel will be programmed to the same params */ + pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio)); + /* TODO : if mask (3 << pipe->first_audio) is used, left and right channel + * will be programmed to the same params + */ if (capture) { rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; - /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled - * (capture pipe level) */ + /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled (capture pipe level) */ rmh.cmd[2] = chip->digital_capture_volume[channel]; } else { - rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | - VALID_AUDIO_IO_MUTE_MONITOR_1; - /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL - * not yet handled (playback pipe level) + rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1; + /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL not yet + * handled (playback pipe level) */ rmh.cmd[2] = chip->monitoring_volume[channel] << 10; if (chip->monitoring_active[channel] == 0) @@ -334,8 +284,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); - if (err < 0) { - snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n", + if(err<0) { + snd_printk(KERN_DEBUG "error update_audio_level card(%d) err(%x)\n", chip->chip_idx, err); return -EINVAL; } @@ -359,15 +309,15 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int *stored_volume; int is_capture = kcontrol->private_value; mutex_lock(&chip->mgr->mixer_mutex); - if (is_capture) /* digital capture */ - stored_volume = chip->digital_capture_volume; - else /* digital playback */ - stored_volume = chip->digital_playback_volume[idx]; + if (is_capture) + stored_volume = chip->digital_capture_volume; /* digital capture */ + else + stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ ucontrol->value.integer.value[0] = stored_volume[0]; ucontrol->value.integer.value[1] = stored_volume[1]; mutex_unlock(&chip->mgr->mixer_mutex); @@ -378,7 +328,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int changed = 0; int is_capture = kcontrol->private_value; int *stored_volume; @@ -434,8 +384,7 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, return 0; } -static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int changed = 0; @@ -495,8 +444,8 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { chip->monitoring_volume[i] = - ucontrol->value.integer.value[i]; - if (chip->monitoring_active[i]) + !!ucontrol->value.integer.value[i]; + if(chip->monitoring_active[i]) /* update monitoring volume and mute */ /* do only when monitoring is unmuted */ pcxhr_update_audio_pipe_level(chip, 0, i); @@ -511,7 +460,7 @@ static struct snd_kcontrol_new pcxhr_control_monitor_vol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), - .name = "Monitoring Playback Volume", + .name = "Monitoring Volume", .info = pcxhr_digital_vol_info, /* shared */ .get = pcxhr_monitor_vol_get, .put = pcxhr_monitor_vol_put, @@ -562,7 +511,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new pcxhr_control_monitor_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Monitoring Playback Switch", + .name = "Monitoring Switch", .info = pcxhr_sw_info, /* shared */ .get = pcxhr_monitor_sw_get, .put = pcxhr_monitor_sw_put @@ -584,7 +533,7 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) struct pcxhr_rmh rmh; unsigned int mask, reg; unsigned int codec; - int err, changed; + int err, use_src, changed; switch (chip->chip_idx) { case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; @@ -593,10 +542,13 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; default: return -EINVAL; } + reg = 0; /* audio source from analog plug */ + use_src = 0; /* do not activate codec SRC */ + if (chip->audio_capture_source != 0) { reg = mask; /* audio source from digital plug */ - } else { - reg = 0; /* audio source from analog plug */ + if (chip->audio_capture_source == 2) + use_src = 1; } /* set the input source */ pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); @@ -608,61 +560,29 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) if (err) return err; } - if (chip->mgr->board_aes_in_192k) { - int i; - unsigned int src_config = 0xC0; - /* update all src configs with one call */ - for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { - if (chip->mgr->chip[i]->audio_capture_source == 2) - src_config |= (1 << (3 - i)); - } - /* set codec SRC on off */ - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); - rmh.cmd_len = 2; - rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; - rmh.cmd[1] = src_config; - err = pcxhr_send_msg(chip->mgr, &rmh); - } else { - int use_src = 0; - if (chip->audio_capture_source == 2) - use_src = 1; - /* set codec SRC on off */ - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); - rmh.cmd_len = 3; - rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; - rmh.cmd[1] = codec; - rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | - (use_src ? 0x41 : 0x54)); - err = pcxhr_send_msg(chip->mgr, &rmh); - if (err) - return err; - rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | - (use_src ? 0x41 : 0x49)); - err = pcxhr_send_msg(chip->mgr, &rmh); - } + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set codec SRC on off */ + rmh.cmd_len = 3; + rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; + rmh.cmd[1] = codec; + rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54); + err = pcxhr_send_msg(chip->mgr, &rmh); + if(err) + return err; + rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49); + err = pcxhr_send_msg(chip->mgr, &rmh); return err; } static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[5] = { - "Line", "Digital", "Digi+SRC", "Mic", "Line+Mic" - }; - int i; - struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + static char *texts[3] = {"Analog", "Digital", "Digi+SRC"}; - i = 2; /* no SRC, no Mic available */ - if (chip->mgr->board_has_aes1) { - i = 3; /* SRC available */ - if (chip->mgr->board_has_mic) - i = 5; /* Mic and MicroMix available */ - } uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = i; - if (uinfo->value.enumerated.item > (i-1)) - uinfo->value.enumerated.item = i-1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item > 2) + uinfo->value.enumerated.item = 2; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; @@ -681,21 +601,13 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int ret = 0; - int i = 2; /* no SRC, no Mic available */ - if (chip->mgr->board_has_aes1) { - i = 3; /* SRC available */ - if (chip->mgr->board_has_mic) - i = 5; /* Mic and MicroMix available */ - } - if (ucontrol->value.enumerated.item[0] >= i) + + if (ucontrol->value.enumerated.item[0] >= 3) return -EINVAL; mutex_lock(&chip->mgr->mixer_mutex); if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { chip->audio_capture_source = ucontrol->value.enumerated.item[0]; - if (chip->mgr->is_hr_stereo) - hr222_set_audio_source(chip); - else - pcxhr_set_audio_source(chip); + pcxhr_set_audio_source(chip); ret = 1; } mutex_unlock(&chip->mgr->mixer_mutex); @@ -714,46 +626,25 @@ static struct snd_kcontrol_new pcxhr_control_audio_src = { /* * clock type selection * enum pcxhr_clock_type { - * PCXHR_CLOCK_TYPE_INTERNAL = 0, - * PCXHR_CLOCK_TYPE_WORD_CLOCK, - * PCXHR_CLOCK_TYPE_AES_SYNC, - * PCXHR_CLOCK_TYPE_AES_1, - * PCXHR_CLOCK_TYPE_AES_2, - * PCXHR_CLOCK_TYPE_AES_3, - * PCXHR_CLOCK_TYPE_AES_4, - * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, - * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, - * HR22_CLOCK_TYPE_AES_SYNC, - * HR22_CLOCK_TYPE_AES_1, - * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, - * }; + * PCXHR_CLOCK_TYPE_INTERNAL = 0, + * PCXHR_CLOCK_TYPE_WORD_CLOCK, + * PCXHR_CLOCK_TYPE_AES_SYNC, + * PCXHR_CLOCK_TYPE_AES_1, + * PCXHR_CLOCK_TYPE_AES_2, + * PCXHR_CLOCK_TYPE_AES_3, + * PCXHR_CLOCK_TYPE_AES_4, + * }; */ static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *textsPCXHR[7] = { - "Internal", "WordClock", "AES Sync", - "AES 1", "AES 2", "AES 3", "AES 4" - }; - static const char *textsHR22[3] = { - "Internal", "AES Sync", "AES 1" + static char *texts[7] = { + "Internal", "WordClock", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" }; - const char **texts; struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); - int clock_items = 2; /* at least Internal and AES Sync clock */ - if (mgr->board_has_aes1) { - clock_items += mgr->capture_chips; /* add AES x */ - if (!mgr->is_hr_stereo) - clock_items += 1; /* add word clock */ - } - if (mgr->is_hr_stereo) { - texts = textsHR22; - snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1)); - } else { - texts = textsPCXHR; - snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); - } + int clock_items = 3 + mgr->capture_chips; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = clock_items; @@ -776,13 +667,9 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); + unsigned int clock_items = 3 + mgr->capture_chips; int rate, ret = 0; - unsigned int clock_items = 2; /* at least Internal and AES Sync clock */ - if (mgr->board_has_aes1) { - clock_items += mgr->capture_chips; /* add AES x */ - if (!mgr->is_hr_stereo) - clock_items += 1; /* add word clock */ - } + if (ucontrol->value.enumerated.item[0] >= clock_items) return -EINVAL; mutex_lock(&mgr->mixer_mutex); @@ -790,8 +677,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, mutex_lock(&mgr->setup_mutex); mgr->use_clock_type = ucontrol->value.enumerated.item[0]; if (mgr->use_clock_type) - pcxhr_get_external_clock(mgr, mgr->use_clock_type, - &rate); + pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate); else rate = mgr->sample_rate; if (rate) { @@ -800,7 +686,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, mgr->sample_rate = rate; } mutex_unlock(&mgr->setup_mutex); - ret = 1; /* return 1 even if the set was not done. ok ? */ + ret = 1; /* return 1 even if the set was not done. ok ? */ } mutex_unlock(&mgr->mixer_mutex); return ret; @@ -861,16 +747,14 @@ static struct snd_kcontrol_new pcxhr_control_clock_rate = { /* * IEC958 status bits */ -static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0; } -static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, - int aes_idx, unsigned char *aes_bits) +static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits) { int i, err; unsigned char temp; @@ -879,61 +763,39 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; switch (chip->chip_idx) { - /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */ - case 0: rmh.cmd[1] = CS8420_01_CS; break; + case 0: rmh.cmd[1] = CS8420_01_CS; break; /* use CS8416_01_CS for AES SYNC plug */ case 1: rmh.cmd[1] = CS8420_23_CS; break; case 2: rmh.cmd[1] = CS8420_45_CS; break; case 3: rmh.cmd[1] = CS8420_67_CS; break; default: return -EINVAL; } - if (chip->mgr->board_aes_in_192k) { - switch (aes_idx) { - case 0: rmh.cmd[2] = CS8416_CSB0; break; - case 1: rmh.cmd[2] = CS8416_CSB1; break; - case 2: rmh.cmd[2] = CS8416_CSB2; break; - case 3: rmh.cmd[2] = CS8416_CSB3; break; - case 4: rmh.cmd[2] = CS8416_CSB4; break; - default: return -EINVAL; - } - } else { - switch (aes_idx) { - /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */ - case 0: rmh.cmd[2] = CS8420_CSB0; break; - case 1: rmh.cmd[2] = CS8420_CSB1; break; - case 2: rmh.cmd[2] = CS8420_CSB2; break; - case 3: rmh.cmd[2] = CS8420_CSB3; break; - case 4: rmh.cmd[2] = CS8420_CSB4; break; - default: return -EINVAL; - } + switch (aes_idx) { + case 0: rmh.cmd[2] = CS8420_CSB0; break; /* use CS8416_CSBx for AES SYNC plug */ + case 1: rmh.cmd[2] = CS8420_CSB1; break; + case 2: rmh.cmd[2] = CS8420_CSB2; break; + case 3: rmh.cmd[2] = CS8420_CSB3; break; + case 4: rmh.cmd[2] = CS8420_CSB4; break; + default: return -EINVAL; } - /* size and code the chip id for the fpga */ - rmh.cmd[1] &= 0x0fffff; - /* chip signature + map for spi read */ - rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; + rmh.cmd[1] &= 0x0fffff; /* size and code the chip id for the fpga */ + rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; /* chip signature + map for spi read */ rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; - - if (chip->mgr->board_aes_in_192k) { - temp = (unsigned char)rmh.stat[1]; - } else { - temp = 0; - /* reversed bit order (not with CS8416_01_CS) */ - for (i = 0; i < 8; i++) { - temp <<= 1; - if (rmh.stat[1] & (1 << i)) - temp |= 1; - } + temp = 0; + for (i = 0; i < 8; i++) { + /* attention : reversed bit order (not with CS8416_01_CS) */ + temp <<= 1; + if (rmh.stat[1] & (1 << i)) + temp |= 1; } - snd_printdd("read iec958 AES %d byte %d = 0x%x\n", - chip->chip_idx, aes_idx, temp); + snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); *aes_bits = temp; return 0; } -static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); unsigned char aes_bits; @@ -944,12 +806,7 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, if (kcontrol->private_value == 0) /* playback */ aes_bits = chip->aes_bits[i]; else { /* capture */ - if (chip->mgr->is_hr_stereo) - err = hr222_iec958_capture_byte(chip, i, - &aes_bits); - else - err = pcxhr_iec958_capture_byte(chip, i, - &aes_bits); + err = pcxhr_iec958_capture_byte(chip, i, &aes_bits); if (err) break; } @@ -968,8 +825,7 @@ static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, - int aes_idx, unsigned char aes_bits) +static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits) { int i, err, cmd; unsigned char new_bits = aes_bits; @@ -978,12 +834,12 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, for (i = 0; i < 8; i++) { if ((old_bits & 0x01) != (new_bits & 0x01)) { - cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ - if (chip->chip_idx > 3) + cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ + if(chip->chip_idx > 3) /* new bit used if chip_idx>3 (PCX1222HR) */ cmd |= 1 << 22; - cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ - cmd |= (new_bits & 0x01) << 23; /* add bit value */ + cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ + cmd |= (new_bits & 0x01) << 23; /* add bit value */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_CUER; rmh.cmd[1] = cmd; @@ -1011,12 +867,7 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, mutex_lock(&chip->mgr->mixer_mutex); for (i = 0; i < 5; i++) { if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { - if (chip->mgr->is_hr_stereo) - hr222_iec958_update_byte(chip, i, - ucontrol->value.iec958.status[i]); - else - pcxhr_iec958_update_byte(chip, i, - ucontrol->value.iec958.status[i]); + pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]); changed = 1; } } @@ -1066,53 +917,29 @@ static void pcxhr_init_audio_levels(struct snd_pcxhr *chip) /* at boot time the digital volumes are unmuted 0dB */ for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { chip->digital_playback_active[j][i] = 1; - chip->digital_playback_volume[j][i] = - PCXHR_DIGITAL_ZERO_LEVEL; + chip->digital_playback_volume[j][i] = PCXHR_DIGITAL_ZERO_LEVEL; } - /* after boot, only two bits are set on the uer - * interface - */ - chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL | - IEC958_AES0_PRO_FS_48000); + /* after boot, only two bits are set on the uer interface */ + chip->aes_bits[0] = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_FS_48000; +/* only for test purpose, remove later */ #ifdef CONFIG_SND_DEBUG - /* analog volumes for playback - * (is LEVEL_MIN after boot) - */ + /* analog volumes for playback (is LEVEL_MIN after boot) */ chip->analog_playback_active[i] = 1; - if (chip->mgr->is_hr_stereo) - chip->analog_playback_volume[i] = - HR222_LINE_PLAYBACK_ZERO_LEVEL; - else { - chip->analog_playback_volume[i] = - PCXHR_LINE_PLAYBACK_ZERO_LEVEL; - pcxhr_update_analog_audio_level(chip, 0, i); - } + chip->analog_playback_volume[i] = PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL; + pcxhr_update_analog_audio_level(chip, 0, i); #endif - /* stereo cards need to be initialised after boot */ - if (chip->mgr->is_hr_stereo) - hr222_update_analog_audio_level(chip, 0, i); +/* test end */ } if (chip->nb_streams_capt) { /* at boot time the digital volumes are unmuted 0dB */ - chip->digital_capture_volume[i] = - PCXHR_DIGITAL_ZERO_LEVEL; - chip->analog_capture_active = 1; + chip->digital_capture_volume[i] = PCXHR_DIGITAL_ZERO_LEVEL; +/* only for test purpose, remove later */ #ifdef CONFIG_SND_DEBUG - /* analog volumes for playback - * (is LEVEL_MIN after boot) - */ - if (chip->mgr->is_hr_stereo) - chip->analog_capture_volume[i] = - HR222_LINE_CAPTURE_ZERO_LEVEL; - else { - chip->analog_capture_volume[i] = - PCXHR_LINE_CAPTURE_ZERO_LEVEL; - pcxhr_update_analog_audio_level(chip, 1, i); - } + /* analog volumes for playback (is LEVEL_MIN after boot) */ + chip->analog_capture_volume[i] = PCXHR_ANALOG_CAPTURE_ZERO_LEVEL; + pcxhr_update_analog_audio_level(chip, 1, i); #endif - /* stereo cards need to be initialised after boot */ - if (chip->mgr->is_hr_stereo) - hr222_update_analog_audio_level(chip, 1, i); +/* test end */ } } @@ -1136,125 +963,90 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) temp = pcxhr_control_analog_level; temp.name = "Master Playback Volume"; temp.private_value = 0; /* playback */ - if (mgr->is_hr_stereo) - temp.tlv.p = db_scale_a_hr222_playback; - else - temp.tlv.p = db_scale_analog_playback; - err = snd_ctl_add(chip->card, - snd_ctl_new1(&temp, chip)); - if (err < 0) + temp.tlv.p = db_scale_analog_playback; + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) return err; - /* output mute controls */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_output_switch, - chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_output_switch, + chip))) < 0) return err; - + temp = snd_pcxhr_pcm_vol; temp.name = "PCM Playback Volume"; temp.count = PCXHR_PLAYBACK_STREAMS; temp.private_value = 0; /* playback */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&temp, chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) return err; - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_pcm_switch, chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_pcm_switch, + chip))) < 0) return err; /* IEC958 controls */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_playback_iec958_mask, - chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_playback_iec958_mask, + chip))) < 0) return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_playback_iec958, - chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_playback_iec958, + chip))) < 0) return err; } if (chip->nb_streams_capt) { - /* analog input level control */ + /* analog input level control only on first two chips !*/ temp = pcxhr_control_analog_level; - temp.name = "Line Capture Volume"; + temp.name = "Master Capture Volume"; temp.private_value = 1; /* capture */ - if (mgr->is_hr_stereo) - temp.tlv.p = db_scale_a_hr222_capture; - else - temp.tlv.p = db_scale_analog_capture; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&temp, chip)); - if (err < 0) + temp.tlv.p = db_scale_analog_capture; + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) return err; temp = snd_pcxhr_pcm_vol; temp.name = "PCM Capture Volume"; temp.count = 1; temp.private_value = 1; /* capture */ - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&temp, chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) return err; - /* Audio source */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_audio_src, chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_audio_src, + chip))) < 0) return err; - /* IEC958 controls */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_capture_iec958_mask, - chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_capture_iec958_mask, + chip))) < 0) return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_capture_iec958, - chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_capture_iec958, + chip))) < 0) return err; - - if (mgr->is_hr_stereo) { - err = hr222_add_mic_controls(chip); - if (err < 0) - return err; - } } /* monitoring only if playback and capture device available */ if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { /* monitoring */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_monitor_vol, chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_monitor_vol, + chip))) < 0) return err; - - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_monitor_sw, chip)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_monitor_sw, + chip))) < 0) return err; } if (i == 0) { /* clock mode only one control per pcxhr */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_clock_type, mgr)); - if (err < 0) + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_clock_type, + mgr))) < 0) return err; - /* non standard control used to scan - * the external clock presence/frequencies - */ - err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_clock_rate, mgr)); - if (err < 0) + /* non standard control used to scan the external clock presence/frequencies */ + if ((err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_clock_rate, + mgr))) < 0) return err; } diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index d0ccfc68c522..e9f0706ed3e4 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -172,7 +172,7 @@ MODULE_PARM_DESC(opl3_port, "OPL3 port # for Riptide driver."); #define MAX_WRITE_RETRY 10 /* cmd interface limits */ #define MAX_ERROR_COUNT 10 -#define CMDIF_TIMEOUT 50000 +#define CMDIF_TIMEOUT 500000 #define RESET_TRIES 5 #define READ_PORT_ULONG(p) inl((unsigned long)&(p)) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index fdd3be5b439d..736246f98acc 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1452,7 +1452,7 @@ static int snd_hdsp_create_midi (struct snd_card *card, struct hdsp *hdsp, int i if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0) return -1; - sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1); + sprintf (hdsp->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); hdsp->midi[id].rmidi->private_data = &hdsp->midi[id]; snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index dc5c4baa1e64..98762f909d64 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1293,7 +1293,7 @@ static int __devinit snd_hdspm_create_midi (struct snd_card *card, if (err < 0) return err; - sprintf(hdspm->midi[id].rmidi->name, "HDSPM MIDI %d", id+1); + sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index af76ee862d27..a38c0c790d2b 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -1033,7 +1033,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) } if (of_device_is_compatible(sound, "tumbler")) { chip->model = PMAC_TUMBLER; - chip->can_capture = machine_is_compatible("PowerMac4,2"); + chip->can_capture = 0; /* no capture */ chip->can_duplex = 0; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->num_freqs = ARRAY_SIZE(tumbler_freqs); diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 3eb223385416..f746e15b8481 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -875,8 +875,7 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = { .put = tumbler_put_master_switch }, DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM), - /* Alternative PCM is assigned to Mic analog loopback on iBook G4 */ - DEFINE_SNAPPER_MIX("Mic Playback Volume", 0, VOL_IDX_PCM2), + DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2), DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC), DEFINE_SNAPPER_MONO("Tone Control - Bass", bass), DEFINE_SNAPPER_MONO("Tone Control - Treble", treble), diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 615ebf0b76e7..4dfda6674bec 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -23,7 +23,8 @@ config SND_SOC_AC97_BUS bool # All the supported Soc's -source "sound/soc/atmel/Kconfig" +source "sound/soc/at32/Kconfig" +source "sound/soc/at91/Kconfig" source "sound/soc/au1x/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 4d475c3ceb91..d849349f2c66 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ atmel/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ 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 @@ +config SND_AT32_SOC + tristate "SoC Audio for the Atmel AT32 System-on-a-Chip" + depends on AVR32 && SND_SOC + help + Say Y or M if you want to add support for codecs attached to + the AT32 SSC interface. You will also need to + to select the audio interfaces to support below. + + +config SND_AT32_SOC_SSC + tristate + + + +config SND_AT32_SOC_PLAYPAQ + tristate "SoC Audio support for PlayPaq with WM8510" + depends on SND_AT32_SOC && BOARD_PLAYPAQ + select SND_AT32_SOC_SSC + select SND_SOC_WM8510 + help + Say Y or M here if you want to add support for SoC audio + on the LRS PlayPaq. + + + +config SND_AT32_SOC_PLAYPAQ_SLAVE + bool "Run CODEC on PlayPaq in slave mode" + depends on SND_AT32_SOC_PLAYPAQ + default n + help + Say Y if you want to run with the AT32 SSC generating the BCLK + and FRAME signals on the PlayPaq. Unless you want to play + with the AT32 as the SSC master, you probably want to say N here, + 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 @@ +# AT32 Platform Support +snd-soc-at32-objs := at32-pcm.o +snd-soc-at32-ssc-objs := at32-ssc.o + +obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o +obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o + +# AT32 Machine Support +snd-soc-playpaq-objs := playpaq_wm8510.o + +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..c83584f989a9 --- /dev/null +++ b/sound/soc/at32/at32-pcm.c @@ -0,0 +1,492 @@ +/* sound/soc/at32/at32-pcm.c + * ASoC PCM interface for Atmel AT32 SoC + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note that this is basically a port of the sound/soc/at91-pcm.c to + * the AVR32 kernel. Thanks to Frank Mandarino for that code. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "at32-pcm.h" + + + +/*--------------------------------------------------------------------------*\ + * Hardware definition +\*--------------------------------------------------------------------------*/ +/* TODO: These values were taken from the AT91 platform driver, check + * them against real values for AT32 + */ +static const struct snd_pcm_hardware at32_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE), + + .formats = SNDRV_PCM_FMTBIT_S16, + .period_bytes_min = 32, + .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */ + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 32 * 1024, +}; + + + +/*--------------------------------------------------------------------------*\ + * Data types +\*--------------------------------------------------------------------------*/ +struct at32_runtime_data { + struct at32_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of DMA buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + + dma_addr_t period_ptr; /* physical address of next period */ + int periods; /* period index of period_ptr */ + + /* Save PDC registers (for power management) */ + u32 pdc_xpr_save; + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + + + +/*--------------------------------------------------------------------------*\ + * Helper functions +\*--------------------------------------------------------------------------*/ +static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *dmabuf = &substream->dma_buffer; + size_t size = at32_pcm_hardware.buffer_bytes_max; + + dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; + dmabuf->dev.dev = pcm->card->dev; + dmabuf->private_data = NULL; + dmabuf->area = dma_alloc_coherent(pcm->card->dev, size, + &dmabuf->addr, GFP_KERNEL); + pr_debug("at32_pcm: preallocate_dma_buffer: " + "area=%p, addr=%p, size=%ld\n", + (void *)dmabuf->area, (void *)dmabuf->addr, size); + + if (!dmabuf->area) + return -ENOMEM; + + dmabuf->bytes = size; + return 0; +} + + + +/*--------------------------------------------------------------------------*\ + * ISR +\*--------------------------------------------------------------------------*/ +static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct at32_runtime_data *prtd = rtd->private_data; + struct at32_pcm_dma_params *params = prtd->params; + static int count; + + count++; + if (ssc_sr & params->mask->ssc_endbuf) { + pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "underrun" : "overrun", params->name, ssc_sr, count); + + /* re-start the PDC */ + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + } + + + if (ssc_sr & params->mask->ssc_endx) { + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + + snd_pcm_period_elapsed(substream); +} + + + +/*--------------------------------------------------------------------------*\ + * PCM operations +\*--------------------------------------------------------------------------*/ +static int at32_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at32_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params + */ + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params->dma_intr_handler = at32_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + pr_debug("hw_params: DMA for %s initialized " + "(dma_bytes=%ld, period_size=%ld)\n", + prtd->params->name, runtime->dma_bytes, prtd->period_size); + + return 0; +} + + + +static int at32_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct at32_runtime_data *prtd = substream->runtime->private_data; + struct at32_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + + + +static int at32_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct at32_runtime_data *prtd = substream->runtime->private_data; + struct at32_pcm_dma_params *params = prtd->params; + + ssc_writex(params->ssc->regs, SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + + return 0; +} + + +static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct at32_runtime_data *prtd = rtd->private_data; + struct at32_pcm_dma_params *params = prtd->params; + int ret = 0; + + pr_debug("at32_pcm_trigger: buffer_size = %ld, " + "dma_area = %p, dma_bytes = %ld\n", + rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + pr_debug("trigger: period_ptr=%lx, xpr=%x, " + "xcr=%d, xnpr=%x, xncr=%d\n", + (unsigned long)prtd->period_ptr, + ssc_readx(params->ssc->regs, params->pdc->xpr), + ssc_readx(params->ssc->regs, params->pdc->xcr), + ssc_readx(params->ssc->regs, params->pdc->xnpr), + ssc_readx(params->ssc->regs, params->pdc->xncr)); + + ssc_writex(params->ssc->regs, SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_enable); + + pr_debug("sr=%x, imr=%x\n", + ssc_readx(params->ssc->regs, SSC_SR), + ssc_readx(params->ssc->regs, SSC_IER)); + break; /* SNDRV_PCM_TRIGGER_START */ + + + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + break; + + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + + + +static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at32_runtime_data *prtd = runtime->private_data; + struct at32_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + + return x; +} + + + +static int at32_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at32_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + +out: + return ret; +} + + + +static int at32_pcm_close(struct snd_pcm_substream *substream) +{ + struct at32_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + + +static int at32_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return remap_pfn_range(vma, vma->vm_start, + substream->dma_buffer.addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); +} + + + +static struct snd_pcm_ops at32_pcm_ops = { + .open = at32_pcm_open, + .close = at32_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = at32_pcm_hw_params, + .hw_free = at32_pcm_hw_free, + .prepare = at32_pcm_prepare, + .trigger = at32_pcm_trigger, + .pointer = at32_pcm_pointer, + .mmap = at32_pcm_mmap, +}; + + + +/*--------------------------------------------------------------------------*\ + * ASoC platform driver +\*--------------------------------------------------------------------------*/ +static u64 at32_pcm_dmamask = 0xffffffff; + +static int at32_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &at32_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = at32_pcm_preallocate_dma_buffer( + pcm, SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n"); + ret = at32_pcm_preallocate_dma_buffer( + pcm, SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + + +out: + return ret; +} + + + +static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (substream == NULL) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + dma_free_coherent(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + + + +#ifdef CONFIG_PM +static int at32_pcm_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at32_runtime_data *prtd; + struct at32_pcm_dma_params *params; + + if (runtime == NULL) + return 0; + prtd = runtime->private_data; + params = prtd->params; + + /* Disable the PDC and save the PDC registers */ + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + + prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); + prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); + prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); + prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); + + return 0; +} + + + +static int at32_pcm_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at32_runtime_data *prtd; + struct at32_pcm_dma_params *params; + + if (runtime == NULL) + return 0; + prtd = runtime->private_data; + params = prtd->params; + + /* Restore the PDC registers and enable the PDC */ + ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); + ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); + ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); + ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); + + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable); + return 0; +} +#else /* CONFIG_PM */ +# define at32_pcm_suspend NULL +# define at32_pcm_resume NULL +#endif /* CONFIG_PM */ + + + +struct snd_soc_platform at32_soc_platform = { + .name = "at32-audio", + .pcm_ops = &at32_pcm_ops, + .pcm_new = at32_pcm_new, + .pcm_free = at32_pcm_free_dma_buffers, + .suspend = at32_pcm_suspend, + .resume = at32_pcm_resume, +}; +EXPORT_SYMBOL_GPL(at32_soc_platform); + + + +MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); +MODULE_DESCRIPTION("Atmel AT32 PCM module"); +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 @@ +/* sound/soc/at32/at32-pcm.h + * ASoC PCM interface for Atmel AT32 SoC + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SOUND_SOC_AT32_AT32_PCM_H +#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__ + +#include <linux/atmel-ssc.h> + + +/* + * Registers and status bits that are required by the PCM driver + * TODO: Is ptcr really used? + */ +struct at32_pdc_regs { + u32 xpr; /* PDC RX/TX pointer */ + u32 xcr; /* PDC RX/TX counter */ + u32 xnpr; /* PDC next RX/TX pointer */ + u32 xncr; /* PDC next RX/TX counter */ + u32 ptcr; /* PDC transfer control */ +}; + + + +/* + * SSC mask info + */ +struct at32_ssc_mask { + u32 ssc_enable; /* SSC RX/TX enable */ + u32 ssc_disable; /* SSC RX/TX disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFF or RXBUFF */ + u32 pdc_enable; /* PDC RX/TX enable */ + u32 pdc_disable; /* PDC RX/TX disable */ +}; + + + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +struct at32_pcm_dma_params { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + struct ssc_device *ssc; /* SSC device for stream */ + struct at32_pdc_regs *pdc; /* PDC register info */ + struct at32_ssc_mask *mask; /* SSC mask info */ + struct snd_pcm_substream *substream; + void (*dma_intr_handler) (u32, struct snd_pcm_substream *); +}; + + + +/* + * The AT32 ASoC platform driver + */ +extern struct snd_soc_platform at32_soc_platform; + + + +/* + * SSC register access (since ssc_writel() / ssc_readl() require literal name) + */ +#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) +#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) + +#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 @@ +/* sound/soc/at32/at32-ssc.c + * ASoC platform driver for AT32 using SSC as DAI + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note that this is basically a port of the sound/soc/at91-ssc.c to + * the AVR32 kernel. Thanks to Frank Mandarino for that code. + */ + +/* #define DEBUG */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/atmel_pdc.h> +#include <linux/atmel-ssc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include "at32-pcm.h" +#include "at32-ssc.h" + + + +/*-------------------------------------------------------------------------*\ + * Constants +\*-------------------------------------------------------------------------*/ +#define NUM_SSC_DEVICES 3 + +/* + * SSC direction masks + */ +#define SSC_DIR_MASK_UNUSED 0 +#define SSC_DIR_MASK_PLAYBACK 1 +#define SSC_DIR_MASK_CAPTURE 2 + +/* + * SSC register values that Atmel left out of <linux/atmel-ssc.h>. These + * are expected to be used with SSC_BF + */ +/* START bit field values */ +#define SSC_START_CONTINUOUS 0 +#define SSC_START_TX_RX 1 +#define SSC_START_LOW_RF 2 +#define SSC_START_HIGH_RF 3 +#define SSC_START_FALLING_RF 4 +#define SSC_START_RISING_RF 5 +#define SSC_START_LEVEL_RF 6 +#define SSC_START_EDGE_RF 7 +#define SSS_START_COMPARE_0 8 + +/* CKI bit field values */ +#define SSC_CKI_FALLING 0 +#define SSC_CKI_RISING 1 + +/* CKO bit field values */ +#define SSC_CKO_NONE 0 +#define SSC_CKO_CONTINUOUS 1 +#define SSC_CKO_TRANSFER 2 + +/* CKS bit field values */ +#define SSC_CKS_DIV 0 +#define SSC_CKS_CLOCK 1 +#define SSC_CKS_PIN 2 + +/* FSEDGE bit field values */ +#define SSC_FSEDGE_POSITIVE 0 +#define SSC_FSEDGE_NEGATIVE 1 + +/* FSOS bit field values */ +#define SSC_FSOS_NONE 0 +#define SSC_FSOS_NEGATIVE 1 +#define SSC_FSOS_POSITIVE 2 +#define SSC_FSOS_LOW 3 +#define SSC_FSOS_HIGH 4 +#define SSC_FSOS_TOGGLE 5 + +#define START_DELAY 1 + + + +/*-------------------------------------------------------------------------*\ + * Module data +\*-------------------------------------------------------------------------*/ +/* + * SSC PDC registered required by the PCM DMA engine + */ +static struct at32_pdc_regs pdc_tx_reg = { + .xpr = SSC_PDC_TPR, + .xcr = SSC_PDC_TCR, + .xnpr = SSC_PDC_TNPR, + .xncr = SSC_PDC_TNCR, +}; + + + +static struct at32_pdc_regs pdc_rx_reg = { + .xpr = SSC_PDC_RPR, + .xcr = SSC_PDC_RCR, + .xnpr = SSC_PDC_RNPR, + .xncr = SSC_PDC_RNCR, +}; + + + +/* + * SSC and PDC status bits for transmit and receive + */ +static struct at32_ssc_mask ssc_tx_mask = { + .ssc_enable = SSC_BIT(CR_TXEN), + .ssc_disable = SSC_BIT(CR_TXDIS), + .ssc_endx = SSC_BIT(SR_ENDTX), + .ssc_endbuf = SSC_BIT(SR_TXBUFE), + .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN), + .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS), +}; + + + +static struct at32_ssc_mask ssc_rx_mask = { + .ssc_enable = SSC_BIT(CR_RXEN), + .ssc_disable = SSC_BIT(CR_RXDIS), + .ssc_endx = SSC_BIT(SR_ENDRX), + .ssc_endbuf = SSC_BIT(SR_RXBUFF), + .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN), + .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS), +}; + + + +/* + * DMA parameters for each SSC + */ +static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { + { + { + .name = "SSC0 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }, + }, + { + { + .name = "SSC1 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }, + }, + { + { + .name = "SSC2 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC2 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }, + }, +}; + + + +static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = { + { + .name = "ssc0", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, + { + .name = "ssc1", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, + { + .name = "ssc2", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, +}; + + + + +/*-------------------------------------------------------------------------*\ + * ISR +\*-------------------------------------------------------------------------*/ +/* + * SSC interrupt handler. Passes PDC interrupts to the DMA interrupt + * handler in the PCM driver. + */ +static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id) +{ + struct at32_ssc_info *ssc_p = dev_id; + struct at32_pcm_dma_params *dma_params; + u32 ssc_sr; + u32 ssc_substream_mask; + int i; + + ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) & + ssc_readl(ssc_p->ssc->regs, IMR)); + + /* + * Loop through substreams attached to this SSC. If a DMA-related + * interrupt occured on that substream, call the DMA interrupt + * handler function, if one has been registered in the dma_param + * structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if ((dma_params != NULL) && + (dma_params->dma_intr_handler != NULL)) { + ssc_substream_mask = (dma_params->mask->ssc_endx | + dma_params->mask->ssc_endbuf); + if (ssc_sr & ssc_substream_mask) { + dma_params->dma_intr_handler(ssc_sr, + dma_params-> + substream); + } + } + } + + + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*\ + * DAI functions +\*-------------------------------------------------------------------------*/ +/* + * Startup. Only that one substream allowed in each direction. + */ +static int at32_ssc_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + int dir_mask; + + dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE); + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + + + +/* + * Shutdown. Clear DMA parameters and shutdown the SSC if there + * are no other substreams open. + */ +static void at32_ssc_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at32_pcm_dma_params *dma_params; + int dir_mask; + + dma_params = ssc_p->dma_params[substream->stream]; + + if (dma_params != NULL) { + ssc_writel(dma_params->ssc->regs, CR, + dma_params->mask->ssc_disable); + pr_debug("%s disabled SSC_SR=0x%08x\n", + (substream->stream ? "receiver" : "transmit"), + ssc_readl(ssc_p->ssc->regs, SR)); + + dma_params->ssc = NULL; + dma_params->substream = NULL; + ssc_p->dma_params[substream->stream] = NULL; + } + + + dir_mask = 1 << substream->stream; + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + /* Shutdown the SSC clock */ + pr_debug("at32-ssc: Stopping user %d clock\n", + ssc_p->ssc->user); + clk_disable(ssc_p->ssc->clk); + + if (ssc_p->initialized) { + free_irq(ssc_p->ssc->irq, ssc_p); + ssc_p->initialized = 0; + } + + /* Reset the SSC */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + + /* clear the SSC dividers */ + ssc_p->cmr_div = 0; + ssc_p->tcmr_period = 0; + ssc_p->rcmr_period = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + + + +/* + * Set the SSC system clock rate + */ +static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + /* TODO: What the heck do I do here? */ + return 0; +} + + + +/* + * Record DAI format for use by hw_params() + */ +static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + ssc_p->daifmt = fmt; + return 0; +} + + + +/* + * Record SSC clock dividers for use in hw_params() + */ +static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + switch (div_id) { + case AT32_SSC_CMR_DIV: + /* + * The same master clock divider is used for both + * transmit and receive, so if a value has already + * been set, it must match this value + */ + if (ssc_p->cmr_div == 0) + ssc_p->cmr_div = div; + else if (div != ssc_p->cmr_div) + return -EBUSY; + break; + + case AT32_SSC_TCMR_PERIOD: + ssc_p->tcmr_period = div; + break; + + case AT32_SSC_RCMR_PERIOD: + ssc_p->rcmr_period = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + + + +/* + * Configure the SSC + */ +static int at32_ssc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->dai->cpu_dai->id; + struct at32_ssc_info *ssc_p = &ssc_info[id]; + struct at32_pcm_dma_params *dma_params; + int channels, bits; + u32 tfmr, rfmr, tcmr, rcmr; + int start_event; + int ret; + + + /* + * Currently, there is only one set of dma_params for each direction. + * If more are added, this code will have to be changed to select + * the proper set + */ + dma_params = &ssc_dma_params[id][substream->stream]; + dma_params->ssc = ssc_p->ssc; + dma_params->substream = substream; + + ssc_p->dma_params[substream->stream] = dma_params; + + + /* + * The cpu_dai->dma_data field is only used to communicate the + * appropriate DMA parameters to the PCM driver's hw_params() + * function. It should not be used for other purposes as it + * is common to all substreams. + */ + rtd->dai->cpu_dai->dma_data = dma_params; + + channels = params_channels(params); + + + /* + * Determine sample size in bits and the PDC increment + */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bits = 8; + dma_params->pdc_xfer_size = 1; + break; + + case SNDRV_PCM_FORMAT_S16: + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + + case SNDRV_PCM_FORMAT_S24: + bits = 24; + dma_params->pdc_xfer_size = 4; + break; + + case SNDRV_PCM_FORMAT_S32: + bits = 32; + dma_params->pdc_xfer_size = 4; + break; + + default: + pr_warning("at32-ssc: Unsupported PCM format %d", + params_format(params)); + return -EINVAL; + } + pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", + bits, dma_params->pdc_xfer_size, channels); + + + /* + * The SSC only supports up to 16-bit samples in I2S format, due + * to the size of the Frame Mode Register FSLEN field. + */ + if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) + if (bits > 16) { + pr_warning("at32-ssc: " + "sample size %d is too large for I2S\n", + bits); + return -EINVAL; + } + + + /* + * Compute the SSC register settings + */ + switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | + SND_SOC_DAIFMT_MASTER_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + /* + * I2S format, SSC provides BCLK and LRS clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line + */ + pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); + rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | + SSC_BF(RCMR_STTDLY, START_DELAY) | + SSC_BF(RCMR_START, SSC_START_FALLING_RF) | + SSC_BF(RCMR_CKI, SSC_CKI_RISING) | + SSC_BF(RCMR_CKO, SSC_CKO_NONE) | + SSC_BF(RCMR_CKS, SSC_CKS_DIV)); + + rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | + SSC_BF(RFMR_FSLEN, bits - 1) | + SSC_BF(RFMR_DATNB, channels - 1) | + SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); + + tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | + SSC_BF(TCMR_STTDLY, START_DELAY) | + SSC_BF(TCMR_START, SSC_START_FALLING_RF) | + SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | + SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | + SSC_BF(TCMR_CKS, SSC_CKS_DIV)); + + tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | + SSC_BF(TFMR_FSLEN, bits - 1) | + SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | + SSC_BF(TFMR_DATLEN, bits - 1)); + break; + + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + /* + * I2S format, CODEC supplies BCLK and LRC clock. + * + * The SSC transmit clock is obtained from the BCLK signal + * on the TK line, and the SSC receive clock is generated from + * the transmit clock. + * + * For single channel data, one sample is transferred on the + * falling edge of the LRC clock. For two channel data, one + * sample is transferred on both edges of the LRC clock. + */ + pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); + start_event = ((channels == 1) ? + SSC_START_FALLING_RF : SSC_START_EDGE_RF); + + rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | + SSC_BF(RCMR_START, start_event) | + SSC_BF(RCMR_CKI, SSC_CKI_RISING) | + SSC_BF(RCMR_CKO, SSC_CKO_NONE) | + SSC_BF(RCMR_CKS, SSC_CKS_CLOCK)); + + rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | + SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); + + tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | + SSC_BF(TCMR_START, start_event) | + SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | + SSC_BF(TCMR_CKO, SSC_CKO_NONE) | + SSC_BF(TCMR_CKS, SSC_CKS_PIN)); + + tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | + SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); + break; + + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + /* + * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line + */ + pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); + rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | + SSC_BF(RCMR_STTDLY, 1) | + SSC_BF(RCMR_START, SSC_START_RISING_RF) | + SSC_BF(RCMR_CKI, SSC_CKI_RISING) | + SSC_BF(RCMR_CKO, SSC_CKO_NONE) | + SSC_BF(RCMR_CKS, SSC_CKS_DIV)); + + rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | + SSC_BF(RFMR_DATNB, channels - 1) | + SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); + + tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | + SSC_BF(TCMR_STTDLY, 1) | + SSC_BF(TCMR_START, SSC_START_RISING_RF) | + SSC_BF(TCMR_CKI, SSC_CKI_RISING) | + SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | + SSC_BF(TCMR_CKS, SSC_CKS_DIV)); + + tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | + SSC_BF(TFMR_DATNB, channels - 1) | + SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); + break; + + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + default: + pr_warning("at32-ssc: unsupported DAI format 0x%x\n", + ssc_p->daifmt); + return -EINVAL; + break; + } + pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", + rcmr, rfmr, tcmr, tfmr); + + + if (!ssc_p->initialized) { + /* enable peripheral clock */ + pr_debug("at32-ssc: Starting clock\n"); + clk_enable(ssc_p->ssc->clk); + + /* Reset the SSC and its PDC registers */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + + ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); + + ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); + + ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, + ssc_p->name, ssc_p); + if (ret < 0) { + pr_warning("at32-ssc: request irq failed (%d)\n", ret); + pr_debug("at32-ssc: Stopping clock\n"); + clk_disable(ssc_p->ssc->clk); + return ret; + } + + ssc_p->initialized = 1; + } + + /* Set SSC clock mode register */ + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); + + /* set receive clock mode and format */ + ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); + + /* set transmit clock mode and format */ + ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); + ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); + + pr_debug("at32-ssc: SSC initialized\n"); + return 0; +} + + + +static int at32_ssc_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at32_pcm_dma_params *dma_params; + + dma_params = ssc_p->dma_params[substream->stream]; + + ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable); + + return 0; +} + + + +#ifdef CONFIG_PM +static int at32_ssc_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at32_ssc_info *ssc_p; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* Save the status register before disabling transmit and receive */ + ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); + + /* Save the current interrupt mask, then disable unmasked interrupts */ + ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); + ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); + + ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); + ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); + ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); + ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); + ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); + + return 0; +} + + + +static int at32_ssc_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at32_ssc_info *ssc_p; + u32 cr; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* restore SSC register settings */ + ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); + ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); + ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); + + /* re-enable interrupts */ + ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); + + /* Re-enable recieve and transmit as appropriate */ + cr = 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; + ssc_writel(ssc_p->ssc->regs, CR, cr); + + return 0; +} +#else /* CONFIG_PM */ +# define at32_ssc_suspend NULL +# define at32_ssc_resume NULL +#endif /* CONFIG_PM */ + + +#define AT32_SSC_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + + +#define AT32_SSC_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16 | \ + SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32) + + +struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = { + { + .name = "at32-ssc0", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = at32_ssc_suspend, + .resume = at32_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .ops = { + .startup = at32_ssc_startup, + .shutdown = at32_ssc_shutdown, + .prepare = at32_ssc_prepare, + .hw_params = at32_ssc_hw_params, + }, + .dai_ops = { + .set_sysclk = at32_ssc_set_dai_sysclk, + .set_fmt = at32_ssc_set_dai_fmt, + .set_clkdiv = at32_ssc_set_dai_clkdiv, + }, + .private_data = &ssc_info[0], + }, + { + .name = "at32-ssc1", + .id = 1, + .type = SND_SOC_DAI_PCM, + .suspend = at32_ssc_suspend, + .resume = at32_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .ops = { + .startup = at32_ssc_startup, + .shutdown = at32_ssc_shutdown, + .prepare = at32_ssc_prepare, + .hw_params = at32_ssc_hw_params, + }, + .dai_ops = { + .set_sysclk = at32_ssc_set_dai_sysclk, + .set_fmt = at32_ssc_set_dai_fmt, + .set_clkdiv = at32_ssc_set_dai_clkdiv, + }, + .private_data = &ssc_info[1], + }, + { + .name = "at32-ssc2", + .id = 2, + .type = SND_SOC_DAI_PCM, + .suspend = at32_ssc_suspend, + .resume = at32_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .ops = { + .startup = at32_ssc_startup, + .shutdown = at32_ssc_shutdown, + .prepare = at32_ssc_prepare, + .hw_params = at32_ssc_hw_params, + }, + .dai_ops = { + .set_sysclk = at32_ssc_set_dai_sysclk, + .set_fmt = at32_ssc_set_dai_fmt, + .set_clkdiv = at32_ssc_set_dai_clkdiv, + }, + .private_data = &ssc_info[2], + }, +}; +EXPORT_SYMBOL_GPL(at32_ssc_dai); + + +MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); +MODULE_DESCRIPTION("AT32 SSC ASoC Interface"); +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 @@ +/* sound/soc/at32/at32-ssc.h + * ASoC SSC interface for Atmel AT32 SoC + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SOUND_SOC_AT32_AT32_SSC_H +#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__ + +#include <linux/types.h> +#include <linux/atmel-ssc.h> + +#include "at32-pcm.h" + + + +struct at32_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + + + +struct at32_ssc_info { + char *name; + struct ssc_device *ssc; + spinlock_t lock; /* lock for dir_mask */ + unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ + unsigned short initialized; /* true if SSC has been initialized */ + unsigned short daifmt; + unsigned short cmr_div; + unsigned short tcmr_period; + unsigned short rcmr_period; + struct at32_pcm_dma_params *dma_params[2]; + struct at32_ssc_state ssc_state; +}; + + +/* SSC divider ids */ +#define AT32_SSC_CMR_DIV 0 /* MCK divider for BCLK */ +#define AT32_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ +#define AT32_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ + + +extern struct snd_soc_dai at32_ssc_dai[]; + + + +#endif /* __SOUND_SOC_AT32_AT32_SSC_H */ diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c index 43dd8cee83c6..b1966e4dfcd3 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/at32/playpaq_wm8510.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/version.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/clk.h> @@ -39,8 +40,8 @@ #include <mach/portmux.h> #include "../codecs/wm8510.h" -#include "atmel-pcm.h" -#include "atmel_ssc_dai.h" +#include "at32-pcm.h" +#include "at32-ssc.h" /*-------------------------------------------------------------------------*\ @@ -361,9 +362,8 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = { -static struct snd_soc_card snd_soc_playpaq = { +static struct snd_soc_machine snd_soc_machine_playpaq = { .name = "LRS_PlayPaq_WM8510", - .platform = &at32_soc_platform, .dai_link = &playpaq_wm8510_dai, .num_links = 1, }; @@ -378,7 +378,8 @@ static struct wm8510_setup_data playpaq_wm8510_setup = { static struct snd_soc_device playpaq_wm8510_snd_devdata = { - .card = &snd_soc_playpaq, + .machine = &snd_soc_machine_playpaq, + .platform = &at32_soc_platform, .codec_dev = &soc_codec_dev_wm8510, .codec_data = &playpaq_wm8510_setup, }; diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig new file mode 100644 index 000000000000..85a883299c2e --- /dev/null +++ b/sound/soc/at91/Kconfig @@ -0,0 +1,10 @@ +config SND_AT91_SOC + tristate "SoC Audio for the Atmel AT91 System-on-Chip" + depends on ARCH_AT91 + help + Say Y or M if you want to add support for codecs attached to + the AT91 SSC interface. You will also need + to select the audio interfaces to support below. + +config SND_AT91_SOC_SSC + tristate diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile new file mode 100644 index 000000000000..b817f11df286 --- /dev/null +++ b/sound/soc/at91/Makefile @@ -0,0 +1,6 @@ +# AT91 Platform Support +snd-soc-at91-objs := at91-pcm.o +snd-soc-at91-ssc-objs := at91-ssc.o + +obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o +obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c new file mode 100644 index 000000000000..7ab48bd25e4c --- /dev/null +++ b/sound/soc/at91/at91-pcm.c @@ -0,0 +1,434 @@ +/* + * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include <mach/hardware.h> +#include <mach/at91_ssc.h> + +#include "at91-pcm.h" + +#if 0 +#define DBG(x...) printk(KERN_INFO "at91-pcm: " x) +#else +#define DBG(x...) +#endif + +static const struct snd_pcm_hardware at91_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 32 * 1024, +}; + +struct at91_runtime_data { + struct at91_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of dma buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + dma_addr_t period_ptr; /* physical address of next period */ + u32 pdc_xpr_save; /* PDC register save */ + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + +static void at91_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + static int count = 0; + + count++; + + if (ssc_sr & params->mask->ssc_endbuf) { + + printk(KERN_WARNING + "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", + params->name, ssc_sr, count); + + /* re-start the PDC */ + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); + } + + if (ssc_sr & params->mask->ssc_endx) { + + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + at91_ssc_write(params->ssc_base + params->pdc->xnpr, + prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + snd_pcm_period_elapsed(substream); +} + +static int at91_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params */ + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params->dma_intr_handler = at91_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", + prtd->params->name, runtime->dma_bytes, prtd->period_size); + return 0; +} + +static int at91_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + +static int at91_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + + at91_ssc_write(params->ssc_base + AT91_SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + return 0; +} + +static int at91_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", + (unsigned long) prtd->period_ptr, + at91_ssc_read(params->ssc_base + params->pdc->xpr), + at91_ssc_read(params->ssc_base + params->pdc->xcr), + at91_ssc_read(params->ssc_base + params->pdc->xnpr), + at91_ssc_read(params->ssc_base + params->pdc->xncr)); + + at91_ssc_write(params->ssc_base + AT91_SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, + params->mask->pdc_enable); + + DBG("sr=%lx imr=%lx\n", + at91_ssc_read(params->ssc_base + AT91_SSC_SR), + at91_ssc_read(params->ssc_base + AT91_SSC_IMR)); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t at91_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd = runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + return x; +} + +static int at91_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + out: + return ret; +} + +static int at91_pcm_close(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static int at91_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +struct snd_pcm_ops at91_pcm_ops = { + .open = at91_pcm_open, + .close = at91_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = at91_pcm_hw_params, + .hw_free = at91_pcm_hw_free, + .prepare = at91_pcm_prepare, + .trigger = at91_pcm_trigger, + .pointer = at91_pcm_pointer, + .mmap = at91_pcm_mmap, +}; + +static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = at91_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + + DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", + (void *) buf->area, + (void *) buf->addr, + size); + + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} + +static u64 at91_pcm_dmamask = 0xffffffff; + +static int at91_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &at91_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = at91_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = at91_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +#ifdef CONFIG_PM +static int at91_pcm_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91_runtime_data *prtd; + struct at91_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* disable the PDC and save the PDC registers */ + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + + prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr); + prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr); + prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr); + prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr); + + return 0; +} + +static int at91_pcm_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91_runtime_data *prtd; + struct at91_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* restore the PDC registers and enable the PDC */ + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save); + at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save); + at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save); + at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); + return 0; +} +#else +#define at91_pcm_suspend NULL +#define at91_pcm_resume NULL +#endif + +struct snd_soc_platform at91_soc_platform = { + .name = "at91-audio", + .pcm_ops = &at91_pcm_ops, + .pcm_new = at91_pcm_new, + .pcm_free = at91_pcm_free_dma_buffers, + .suspend = at91_pcm_suspend, + .resume = at91_pcm_resume, +}; + +EXPORT_SYMBOL_GPL(at91_soc_platform); + +MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>"); +MODULE_DESCRIPTION("Atmel AT91 PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h new file mode 100644 index 000000000000..e5aada2cb102 --- /dev/null +++ b/sound/soc/at91/at91-pcm.h @@ -0,0 +1,72 @@ +/* + * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.h by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _AT91_PCM_H +#define _AT91_PCM_H + +#include <mach/hardware.h> + +struct at91_ssc_periph { + void __iomem *base; + u32 pid; +}; + +/* + * Registers and status bits that are required by the PCM driver. + */ +struct at91_pdc_regs { + unsigned int xpr; /* PDC recv/trans pointer */ + unsigned int xcr; /* PDC recv/trans counter */ + unsigned int xnpr; /* PDC next recv/trans pointer */ + unsigned int xncr; /* PDC next recv/trans counter */ + unsigned int ptcr; /* PDC transfer control */ +}; + +struct at91_ssc_mask { + u32 ssc_enable; /* SSC recv/trans enable */ + u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ + u32 pdc_enable; /* PDC recv/trans enable */ + u32 pdc_disable; /* PDC recv/trans disable */ +}; + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +struct at91_pcm_dma_params { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + void __iomem *ssc_base; /* SSC base address */ + struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */ + struct at91_ssc_mask *mask;/* SSC & PDC status bits */ + struct snd_pcm_substream *substream; + void (*dma_intr_handler)(u32, struct snd_pcm_substream *); +}; + +extern struct snd_soc_platform at91_soc_platform; + +#define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) +#define at91_ssc_write(a,v) __raw_writel((v),(a)) + +#endif /* _AT91_PCM_H */ diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c new file mode 100644 index 000000000000..1b61cc461261 --- /dev/null +++ b/sound/soc/at91/at91-ssc.c @@ -0,0 +1,791 @@ +/* + * at91-ssc.c -- ALSA SoC AT91 SSC Audio Layer Platform driver + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * + * Based on pxa2xx Platform drivers by + * Liam Girdwood <lrg@slimlogic.co.uk> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/atmel_pdc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <mach/hardware.h> +#include <mach/at91_pmc.h> +#include <mach/at91_ssc.h> + +#include "at91-pcm.h" +#include "at91-ssc.h" + +#if 0 +#define DBG(x...) printk(KERN_DEBUG "at91-ssc:" x) +#else +#define DBG(x...) +#endif + +#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) +#define NUM_SSC_DEVICES 1 +#else +#define NUM_SSC_DEVICES 3 +#endif + + +/* + * SSC PDC registers required by the PCM DMA engine. + */ +static struct at91_pdc_regs pdc_tx_reg = { + .xpr = ATMEL_PDC_TPR, + .xcr = ATMEL_PDC_TCR, + .xnpr = ATMEL_PDC_TNPR, + .xncr = ATMEL_PDC_TNCR, +}; + +static struct at91_pdc_regs pdc_rx_reg = { + .xpr = ATMEL_PDC_RPR, + .xcr = ATMEL_PDC_RCR, + .xnpr = ATMEL_PDC_RNPR, + .xncr = ATMEL_PDC_RNCR, +}; + +/* + * SSC & PDC status bits for transmit and receive. + */ +static struct at91_ssc_mask ssc_tx_mask = { + .ssc_enable = AT91_SSC_TXEN, + .ssc_disable = AT91_SSC_TXDIS, + .ssc_endx = AT91_SSC_ENDTX, + .ssc_endbuf = AT91_SSC_TXBUFE, + .pdc_enable = ATMEL_PDC_TXTEN, + .pdc_disable = ATMEL_PDC_TXTDIS, +}; + +static struct at91_ssc_mask ssc_rx_mask = { + .ssc_enable = AT91_SSC_RXEN, + .ssc_disable = AT91_SSC_RXDIS, + .ssc_endx = AT91_SSC_ENDRX, + .ssc_endbuf = AT91_SSC_RXBUFF, + .pdc_enable = ATMEL_PDC_RXTEN, + .pdc_disable = ATMEL_PDC_RXTDIS, +}; + + +/* + * DMA parameters. + */ +static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { + {{ + .name = "SSC0 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, +#if NUM_SSC_DEVICES == 3 + {{ + .name = "SSC1 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, + {{ + .name = "SSC2 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC2 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, +#endif +}; + +struct at91_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + +static struct at91_ssc_info { + char *name; + struct at91_ssc_periph ssc; + spinlock_t lock; /* lock for dir_mask */ + unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ + unsigned short initialized; /* 1=SSC has been initialized */ + unsigned short daifmt; + unsigned short cmr_div; + unsigned short tcmr_period; + unsigned short rcmr_period; + struct at91_pcm_dma_params *dma_params[2]; + struct at91_ssc_state ssc_state; + +} ssc_info[NUM_SSC_DEVICES] = { + { + .name = "ssc0", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), + .dir_mask = 0, + .initialized = 0, + }, +#if NUM_SSC_DEVICES == 3 + { + .name = "ssc1", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), + .dir_mask = 0, + .initialized = 0, + }, + { + .name = "ssc2", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), + .dir_mask = 0, + .initialized = 0, + }, +#endif +}; + +static unsigned int at91_ssc_sysclk; + +/* + * SSC interrupt handler. Passes PDC interrupts to the DMA + * interrupt handler in the PCM driver. + */ +static irqreturn_t at91_ssc_interrupt(int irq, void *dev_id) +{ + struct at91_ssc_info *ssc_p = dev_id; + struct at91_pcm_dma_params *dma_params; + u32 ssc_sr; + int i; + + ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR) + & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + + /* + * Loop through the substreams attached to this SSC. If + * a DMA-related interrupt occurred on that substream, call + * the DMA interrupt handler function, if one has been + * registered in the dma_params structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if (dma_params != NULL && dma_params->dma_intr_handler != NULL && + (ssc_sr & + (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) + + dma_params->dma_intr_handler(ssc_sr, dma_params->substream); + } + + return IRQ_HANDLED; +} + +/* + * Startup. Only that one substream allowed in each direction. + */ +static int at91_ssc_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + int dir_mask; + + DBG("ssc_startup: SSC_SR=0x%08lx\n", + at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); + dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + +/* + * Shutdown. Clear DMA parameters and shutdown the SSC if there + * are no other substreams open. + */ +static void at91_ssc_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at91_pcm_dma_params *dma_params; + int dir, dir_mask; + + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + dma_params = ssc_p->dma_params[dir]; + + if (dma_params != NULL) { + at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, + dma_params->mask->ssc_disable); + DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), + at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); + + dma_params->ssc_base = NULL; + dma_params->substream = NULL; + ssc_p->dma_params[dir] = NULL; + } + + dir_mask = 1 << dir; + + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + /* Shutdown the SSC clock. */ + DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid); + + if (ssc_p->initialized) { + free_irq(ssc_p->ssc.pid, ssc_p); + ssc_p->initialized = 0; + } + + /* Reset the SSC */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); + + /* Clear the SSC dividers */ + ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + +/* + * Record the SSC system clock rate. + */ +static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + /* + * The only clock supplied to the SSC is the AT91 master clock, + * which is only used if the SSC is generating BCLK and/or + * LRC clocks. + */ + switch (clk_id) { + case AT91_SYSCLK_MCK: + at91_ssc_sysclk = freq; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * Record the DAI format for use in hw_params(). + */ +static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + ssc_p->daifmt = fmt; + return 0; +} + +/* + * Record SSC clock dividers for use in hw_params(). + */ +static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + switch (div_id) { + case AT91SSC_CMR_DIV: + /* + * The same master clock divider is used for both + * transmit and receive, so if a value has already + * been set, it must match this value. + */ + if (ssc_p->cmr_div == 0) + ssc_p->cmr_div = div; + else + if (div != ssc_p->cmr_div) + return -EBUSY; + break; + + case AT91SSC_TCMR_PERIOD: + ssc_p->tcmr_period = div; + break; + + case AT91SSC_RCMR_PERIOD: + ssc_p->rcmr_period = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Configure the SSC. + */ +static int at91_ssc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->dai->cpu_dai->id; + struct at91_ssc_info *ssc_p = &ssc_info[id]; + struct at91_pcm_dma_params *dma_params; + int dir, channels, bits; + u32 tfmr, rfmr, tcmr, rcmr; + int start_event; + int ret; + + /* + * Currently, there is only one set of dma params for + * each direction. If more are added, this code will + * have to be changed to select the proper set. + */ + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + + dma_params = &ssc_dma_params[id][dir]; + dma_params->ssc_base = ssc_p->ssc.base; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + + /* + * The cpu_dai->dma_data field is only used to communicate the + * appropriate DMA parameters to the pcm driver hw_params() + * function. It should not be used for other purposes + * as it is common to all substreams. + */ + rtd->dai->cpu_dai->dma_data = dma_params; + + channels = params_channels(params); + + /* + * Determine sample size in bits and the PDC increment. + */ + switch(params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bits = 8; + dma_params->pdc_xfer_size = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bits = 24; + dma_params->pdc_xfer_size = 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bits = 32; + dma_params->pdc_xfer_size = 4; + break; + default: + printk(KERN_WARNING "at91-ssc: unsupported PCM format\n"); + return -EINVAL; + } + + /* + * The SSC only supports up to 16-bit samples in I2S format, due + * to the size of the Frame Mode Register FSLEN field. + */ + if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S + && bits > 16) { + printk(KERN_WARNING + "at91-ssc: sample size %d is too large for I2S\n", bits); + return -EINVAL; + } + + /* + * Compute SSC register settings. + */ + switch (ssc_p->daifmt + & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + /* + * I2S format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line. + */ + rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + break; + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + /* + * I2S format, CODEC supplies BCLK and LRC clocks. + * + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is generated from the + * transmit clock. + * + * For single channel data, one sample is transferred on the falling + * edge of the LRC clock. For two channel data, one sample is + * transferred on both edges of the LRC clock. + */ + start_event = channels == 1 + ? AT91_SSC_START_FALLING_RF + : AT91_SSC_START_EDGE_RF; + + rcmr = (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( start_event ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (( 0 << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( start_event ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (( 0 << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + /* + * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line. + */ + rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + + + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + default: + printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n", + ssc_p->daifmt); + return -EINVAL; + break; + } + DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); + + if (!ssc_p->initialized) { + + /* Enable PMC peripheral clock for this SSC */ + DBG("Starting pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid); + + /* Reset the SSC and its PDC registers */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); + + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0); + + if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt, + 0, ssc_p->name, ssc_p)) < 0) { + printk(KERN_WARNING "at91-ssc: request_irq failure\n"); + + DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid); + return ret; + } + + ssc_p->initialized = 1; + } + + /* set SSC clock mode register */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div); + + /* set receive clock mode and format */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); + + /* set transmit clock mode and format */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); + + DBG("hw_params: SSC initialized\n"); + return 0; +} + + +static int at91_ssc_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at91_pcm_dma_params *dma_params; + int dir; + + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + dma_params = ssc_p->dma_params[dir]; + + at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, + dma_params->mask->ssc_enable); + + DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit", + at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR)); + return 0; +} + + +#ifdef CONFIG_PM +static int at91_ssc_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at91_ssc_info *ssc_p; + + if(!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* Save the status register before disabling transmit and receive. */ + ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, + AT91_SSC_TXDIS | AT91_SSC_RXDIS); + + /* Save the current interrupt mask, then disable unmasked interrupts. */ + ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); + + ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); + ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR); + ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR); + ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR); + + return 0; +} + +static int at91_ssc_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at91_ssc_info *ssc_p; + + if(!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); + + return 0; +} + +#else +#define at91_ssc_suspend NULL +#define at91_ssc_resume NULL +#endif + +#define AT91_SSC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000) + +#define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = { + { .name = "at91-ssc0", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = at91_ssc_suspend, + .resume = at91_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .ops = { + .startup = at91_ssc_startup, + .shutdown = at91_ssc_shutdown, + .prepare = at91_ssc_prepare, + .hw_params = at91_ssc_hw_params,}, + .dai_ops = { + .set_sysclk = at91_ssc_set_dai_sysclk, + .set_fmt = at91_ssc_set_dai_fmt, + .set_clkdiv = at91_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[0].ssc, + }, +#if NUM_SSC_DEVICES == 3 + { .name = "at91-ssc1", + .id = 1, + .type = SND_SOC_DAI_PCM, + .suspend = at91_ssc_suspend, + .resume = at91_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .ops = { + .startup = at91_ssc_startup, + .shutdown = at91_ssc_shutdown, + .prepare = at91_ssc_prepare, + .hw_params = at91_ssc_hw_params,}, + .dai_ops = { + .set_sysclk = at91_ssc_set_dai_sysclk, + .set_fmt = at91_ssc_set_dai_fmt, + .set_clkdiv = at91_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[1].ssc, + }, + { .name = "at91-ssc2", + .id = 2, + .type = SND_SOC_DAI_PCM, + .suspend = at91_ssc_suspend, + .resume = at91_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .ops = { + .startup = at91_ssc_startup, + .shutdown = at91_ssc_shutdown, + .prepare = at91_ssc_prepare, + .hw_params = at91_ssc_hw_params,}, + .dai_ops = { + .set_sysclk = at91_ssc_set_dai_sysclk, + .set_fmt = at91_ssc_set_dai_fmt, + .set_clkdiv = at91_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[2].ssc, + }, +#endif +}; + +EXPORT_SYMBOL_GPL(at91_ssc_dai); + +/* Module information */ +MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); +MODULE_DESCRIPTION("AT91 SSC ASoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h new file mode 100644 index 000000000000..6b7bf382d06f --- /dev/null +++ b/sound/soc/at91/at91-ssc.h @@ -0,0 +1,27 @@ +/* + * at91-ssc.h - ALSA SSC interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * Created: Jan 9, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _AT91_SSC_H +#define _AT91_SSC_H + +/* SSC system clock ids */ +#define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ + +/* SSC divider ids */ +#define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */ +#define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ +#define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ + +extern struct snd_soc_dai at91_ssc_dai[]; + +#endif /* _AT91_SSC_H */ + diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig deleted file mode 100644 index a608d7009dbd..000000000000 --- a/sound/soc/atmel/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -config SND_ATMEL_SOC - tristate "SoC Audio for the Atmel System-on-Chip" - depends on ARCH_AT91 || AVR32 - help - Say Y or M if you want to add support for codecs attached to - the ATMEL SSC interface. You will also need - to select the audio interfaces to support below. - -config SND_ATMEL_SOC_SSC - tristate - depends on SND_ATMEL_SOC - help - Say Y or M if you want to add support for codecs the - ATMEL SSC interface. You will also needs to select the individual - machine drivers to support below. - -config SND_AT91_SOC_SAM9G20_WM8731 - tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC - select SND_ATMEL_SOC_SSC - select SND_SOC_WM8731 - help - Say Y if you want to add support for SoC audio on WM8731-based - AT91sam9g20 evaluation board. - -config SND_AT32_SOC_PLAYPAQ - tristate "SoC Audio support for PlayPaq with WM8510" - depends on SND_ATMEL_SOC && BOARD_PLAYPAQ - select SND_ATMEL_SOC_SSC - select SND_SOC_WM8510 - help - Say Y or M here if you want to add support for SoC audio - on the LRS PlayPaq. - -config SND_AT32_SOC_PLAYPAQ_SLAVE - bool "Run CODEC on PlayPaq in slave mode" - depends on SND_AT32_SOC_PLAYPAQ - default n - help - Say Y if you want to run with the AT32 SSC generating the BCLK - and FRAME signals on the PlayPaq. Unless you want to play - with the AT32 as the SSC master, you probably want to say N here, - as this will give you better sound quality. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile deleted file mode 100644 index f54a7cc68e66..000000000000 --- a/sound/soc/atmel/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# AT91 Platform Support -snd-soc-atmel-pcm-objs := atmel-pcm.o -snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o - -obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o -obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o - -# AT91 Machine Support -snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o - -# AT32 Machine Support -snd-soc-playpaq-objs := playpaq_wm8510.o - -obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o -obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c deleted file mode 100644 index 027eb13f9dd0..000000000000 --- a/sound/soc/atmel/atmel-pcm.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * - * Based on at91-pcm. by: - * Frank Mandarino <fmandarino@endrelia.com> - * Copyright 2006 Endrelia Technologies Inc. - * - * Based on pxa2xx-pcm.c by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: (C) 2004 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/dma-mapping.h> -#include <linux/atmel_pdc.h> -#include <linux/atmel-ssc.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include <mach/hardware.h> - -#include "atmel-pcm.h" - - -/*--------------------------------------------------------------------------*\ - * Hardware definition -\*--------------------------------------------------------------------------*/ -/* TODO: These values were taken from the AT91 platform driver, check - * them against real values for AT32 - */ -static const struct snd_pcm_hardware atmel_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - - -/*--------------------------------------------------------------------------*\ - * Data types -\*--------------------------------------------------------------------------*/ -struct atmel_runtime_data { - struct atmel_pcm_dma_params *params; - dma_addr_t dma_buffer; /* physical address of dma buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - - dma_addr_t period_ptr; /* physical address of next period */ - int periods; /* period index of period_ptr */ - - /* PDC register save */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - - -/*--------------------------------------------------------------------------*\ - * Helper functions -\*--------------------------------------------------------------------------*/ -static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, - int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = atmel_pcm_hardware.buffer_bytes_max; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_coherent(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - pr_debug("atmel-pcm:" - "preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, - (void *) buf->addr, - size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} -/*--------------------------------------------------------------------------*\ - * ISR -\*--------------------------------------------------------------------------*/ -static void atmel_pcm_dma_irq(u32 ssc_sr, - struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - static int count; - - count++; - - if (ssc_sr & params->mask->ssc_endbuf) { - pr_warning("atmel-pcm: buffer %s on %s" - " (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? "underrun" : "overrun", - params->name, ssc_sr, count); - - /* re-start the PDC */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - } - - if (ssc_sr & params->mask->ssc_endx) { - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - snd_pcm_period_elapsed(substream); -} - - -/*--------------------------------------------------------------------------*\ - * PCM operations -\*--------------------------------------------------------------------------*/ -static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params */ - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = rtd->dai->cpu_dai->dma_data; - prtd->params->dma_intr_handler = atmel_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - pr_debug("atmel-pcm: " - "hw_params: DMA for %s initialized " - "(dma_bytes=%u, period_size=%u)\n", - prtd->params->name, - runtime->dma_bytes, - prtd->period_size); - return 0; -} - -static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - -static int atmel_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - ssc_writex(params->ssc->regs, SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - return 0; -} - -static int atmel_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct atmel_runtime_data *prtd = rtd->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - int ret = 0; - - pr_debug("atmel-pcm:buffer_size = %ld," - "dma_area = %p, dma_bytes = %u\n", - rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - pr_debug("atmel-pcm: trigger: " - "period_ptr=%lx, xpr=%u, " - "xcr=%u, xnpr=%u, xncr=%u\n", - (unsigned long)prtd->period_ptr, - ssc_readx(params->ssc->regs, params->pdc->xpr), - ssc_readx(params->ssc->regs, params->pdc->xcr), - ssc_readx(params->ssc->regs, params->pdc->xnpr), - ssc_readx(params->ssc->regs, params->pdc->xncr)); - - ssc_writex(params->ssc->regs, SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_enable); - - pr_debug("sr=%u imr=%u\n", - ssc_readx(params->ssc->regs, SSC_SR), - ssc_readx(params->ssc->regs, SSC_IER)); - break; /* SNDRV_PCM_TRIGGER_START */ - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - break; - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static snd_pcm_uframes_t atmel_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - - return x; -} - -static int atmel_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - out: - return ret; -} - -static int atmel_pcm_close(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - -static int atmel_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - return remap_pfn_range(vma, vma->vm_start, - substream->dma_buffer.addr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); -} - -struct snd_pcm_ops atmel_pcm_ops = { - .open = atmel_pcm_open, - .close = atmel_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = atmel_pcm_hw_params, - .hw_free = atmel_pcm_hw_free, - .prepare = atmel_pcm_prepare, - .trigger = atmel_pcm_trigger, - .pointer = atmel_pcm_pointer, - .mmap = atmel_pcm_mmap, -}; - - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ -static u64 atmel_pcm_dmamask = 0xffffffff; - -static int atmel_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &atmel_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = atmel_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - pr_debug("at32-pcm:" - "Allocating PCM capture DMA buffer\n"); - ret = atmel_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - dma_free_coherent(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -#ifdef CONFIG_PM -static int atmel_pcm_suspend(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); - prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); - prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); - prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); - - return 0; -} - -static int atmel_pcm_resume(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); - ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); - ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); - ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else -#define atmel_pcm_suspend NULL -#define atmel_pcm_resume NULL -#endif - -struct snd_soc_platform atmel_soc_platform = { - .name = "atmel-audio", - .pcm_ops = &atmel_pcm_ops, - .pcm_new = atmel_pcm_new, - .pcm_free = atmel_pcm_free_dma_buffers, - .suspend = atmel_pcm_suspend, - .resume = atmel_pcm_resume, -}; -EXPORT_SYMBOL_GPL(atmel_soc_platform); - -static int __devinit atmel_pcm_modinit(void) -{ - return snd_soc_register_platform(&atmel_soc_platform); -} -module_init(atmel_pcm_modinit); - -static void __exit atmel_pcm_modexit(void) -{ - snd_soc_unregister_platform(&atmel_soc_platform); -} -module_exit(atmel_pcm_modexit); - -MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); -MODULE_DESCRIPTION("Atmel PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h deleted file mode 100644 index ec9b2824b663..000000000000 --- a/sound/soc/atmel/atmel-pcm.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC. - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * - * Based on at91-pcm. by: - * Frank Mandarino <fmandarino@endrelia.com> - * Copyright 2006 Endrelia Technologies Inc. - * - * Based on pxa2xx-pcm.c by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: (C) 2004 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ATMEL_PCM_H -#define _ATMEL_PCM_H - -#include <linux/atmel-ssc.h> - -/* - * Registers and status bits that are required by the PCM driver. - */ -struct atmel_pdc_regs { - unsigned int xpr; /* PDC recv/trans pointer */ - unsigned int xcr; /* PDC recv/trans counter */ - unsigned int xnpr; /* PDC next recv/trans pointer */ - unsigned int xncr; /* PDC next recv/trans counter */ - unsigned int ptcr; /* PDC transfer control */ -}; - -struct atmel_ssc_mask { - u32 ssc_enable; /* SSC recv/trans enable */ - u32 ssc_disable; /* SSC recv/trans disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ - u32 pdc_enable; /* PDC recv/trans enable */ - u32 pdc_disable; /* PDC recv/trans disable */ -}; - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -struct atmel_pcm_dma_params { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - struct ssc_device *ssc; /* SSC device for stream */ - struct atmel_pdc_regs *pdc; /* PDC receive or transmit registers */ - struct atmel_ssc_mask *mask; /* SSC & PDC status bits */ - struct snd_pcm_substream *substream; - void (*dma_intr_handler)(u32, struct snd_pcm_substream *); -}; - -extern struct snd_soc_platform atmel_soc_platform; - - -/* - * SSC register access (since ssc_writel() / ssc_readl() require literal name) - */ -#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) -#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) - -#endif /* _ATMEL_PCM_H */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c deleted file mode 100644 index 87904b6ab8c2..000000000000 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ /dev/null @@ -1,790 +0,0 @@ -/* - * atmel_ssc_dai.c -- ALSA SoC ATMEL SSC Audio Layer Platform driver - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * ATMEL CORP. - * - * Based on at91-ssc.c by - * Frank Mandarino <fmandarino@endrelia.com> - * Based on pxa2xx Platform drivers by - * Liam Girdwood <liam.girdwood@wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/atmel_pdc.h> - -#include <linux/atmel-ssc.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> -#include <sound/soc.h> - -#include <mach/hardware.h> - -#include "atmel-pcm.h" -#include "atmel_ssc_dai.h" - - -#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) -#define NUM_SSC_DEVICES 1 -#else -#define NUM_SSC_DEVICES 3 -#endif - -/* - * SSC PDC registers required by the PCM DMA engine. - */ -static struct atmel_pdc_regs pdc_tx_reg = { - .xpr = ATMEL_PDC_TPR, - .xcr = ATMEL_PDC_TCR, - .xnpr = ATMEL_PDC_TNPR, - .xncr = ATMEL_PDC_TNCR, -}; - -static struct atmel_pdc_regs pdc_rx_reg = { - .xpr = ATMEL_PDC_RPR, - .xcr = ATMEL_PDC_RCR, - .xnpr = ATMEL_PDC_RNPR, - .xncr = ATMEL_PDC_RNCR, -}; - -/* - * SSC & PDC status bits for transmit and receive. - */ -static struct atmel_ssc_mask ssc_tx_mask = { - .ssc_enable = SSC_BIT(CR_TXEN), - .ssc_disable = SSC_BIT(CR_TXDIS), - .ssc_endx = SSC_BIT(SR_ENDTX), - .ssc_endbuf = SSC_BIT(SR_TXBUFE), - .pdc_enable = ATMEL_PDC_TXTEN, - .pdc_disable = ATMEL_PDC_TXTDIS, -}; - -static struct atmel_ssc_mask ssc_rx_mask = { - .ssc_enable = SSC_BIT(CR_RXEN), - .ssc_disable = SSC_BIT(CR_RXDIS), - .ssc_endx = SSC_BIT(SR_ENDRX), - .ssc_endbuf = SSC_BIT(SR_RXBUFF), - .pdc_enable = ATMEL_PDC_RXTEN, - .pdc_disable = ATMEL_PDC_RXTDIS, -}; - - -/* - * DMA parameters. - */ -static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - {{ - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, -#if NUM_SSC_DEVICES == 3 - {{ - .name = "SSC1 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, - {{ - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, -#endif -}; - - -static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -#endif -}; - - -/* - * SSC interrupt handler. Passes PDC interrupts to the DMA - * interrupt handler in the PCM driver. - */ -static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) -{ - struct atmel_ssc_info *ssc_p = dev_id; - struct atmel_pcm_dma_params *dma_params; - u32 ssc_sr; - u32 ssc_substream_mask; - int i; - - ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR) - & (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR); - - /* - * Loop through the substreams attached to this SSC. If - * a DMA-related interrupt occurred on that substream, call - * the DMA interrupt handler function, if one has been - * registered in the dma_params structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if ((dma_params != NULL) && - (dma_params->dma_intr_handler != NULL)) { - ssc_substream_mask = (dma_params->mask->ssc_endx | - dma_params->mask->ssc_endbuf); - if (ssc_sr & ssc_substream_mask) { - dma_params->dma_intr_handler(ssc_sr, - dma_params-> - substream); - } - } - } - - return IRQ_HANDLED; -} - - -/*-------------------------------------------------------------------------*\ - * DAI functions -\*-------------------------------------------------------------------------*/ -/* - * Startup. Only that one substream allowed in each direction. - */ -static int atmel_ssc_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - int dir_mask; - - pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", - ssc_readl(ssc_p->ssc->regs, SR)); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir_mask = SSC_DIR_MASK_PLAYBACK; - else - dir_mask = SSC_DIR_MASK_CAPTURE; - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - -/* - * Shutdown. Clear DMA parameters and shutdown the SSC if there - * are no other substreams open. - */ -static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct atmel_pcm_dma_params *dma_params; - int dir, dir_mask; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = 0; - else - dir = 1; - - dma_params = ssc_p->dma_params[dir]; - - if (dma_params != NULL) { - ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable); - pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n", - (dir ? "receive" : "transmit"), - ssc_readl(ssc_p->ssc->regs, SR)); - - dma_params->ssc = NULL; - dma_params->substream = NULL; - ssc_p->dma_params[dir] = NULL; - } - - dir_mask = 1 << dir; - - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - if (ssc_p->initialized) { - /* Shutdown the SSC clock. */ - pr_debug("atmel_ssc_dau: Stopping clock\n"); - clk_disable(ssc_p->ssc->clk); - - free_irq(ssc_p->ssc->irq, ssc_p); - ssc_p->initialized = 0; - } - - /* Reset the SSC */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - /* Clear the SSC dividers */ - ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - - -/* - * Record the DAI format for use in hw_params(). - */ -static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - ssc_p->daifmt = fmt; - return 0; -} - -/* - * Record SSC clock dividers for use in hw_params(). - */ -static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - switch (div_id) { - case ATMEL_SSC_CMR_DIV: - /* - * The same master clock divider is used for both - * transmit and receive, so if a value has already - * been set, it must match this value. - */ - if (ssc_p->cmr_div == 0) - ssc_p->cmr_div = div; - else - if (div != ssc_p->cmr_div) - return -EBUSY; - break; - - case ATMEL_SSC_TCMR_PERIOD: - ssc_p->tcmr_period = div; - break; - - case ATMEL_SSC_RCMR_PERIOD: - ssc_p->rcmr_period = div; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * Configure the SSC. - */ -static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - int id = rtd->dai->cpu_dai->id; - struct atmel_ssc_info *ssc_p = &ssc_info[id]; - struct atmel_pcm_dma_params *dma_params; - int dir, channels, bits; - u32 tfmr, rfmr, tcmr, rcmr; - int start_event; - int ret; - - /* - * Currently, there is only one set of dma params for - * each direction. If more are added, this code will - * have to be changed to select the proper set. - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = 0; - else - dir = 1; - - dma_params = &ssc_dma_params[id][dir]; - dma_params->ssc = ssc_p->ssc; - dma_params->substream = substream; - - ssc_p->dma_params[dir] = dma_params; - - /* - * The cpu_dai->dma_data field is only used to communicate the - * appropriate DMA parameters to the pcm driver hw_params() - * function. It should not be used for other purposes - * as it is common to all substreams. - */ - rtd->dai->cpu_dai->dma_data = dma_params; - - channels = params_channels(params); - - /* - * Determine sample size in bits and the PDC increment. - */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - bits = 8; - dma_params->pdc_xfer_size = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - case SNDRV_PCM_FORMAT_S24_LE: - bits = 24; - dma_params->pdc_xfer_size = 4; - break; - case SNDRV_PCM_FORMAT_S32_LE: - bits = 32; - dma_params->pdc_xfer_size = 4; - break; - default: - printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format"); - return -EINVAL; - } - - /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S - && bits > 16) { - printk(KERN_WARNING - "atmel_ssc_dai: sample size %d" - "is too large for I2S\n", bits); - return -EINVAL; - } - - /* - * Compute SSC register settings. - */ - switch (ssc_p->daifmt - & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated - * from the MCK divider, and the BCLK signal - * is output on the SSC TK line. - */ - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, (bits - 1)) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, (bits - 1)) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* - * I2S format, CODEC supplies BCLK and LRC clocks. - * - * The SSC transmit clock is obtained from the BCLK signal on - * on the TK line, and the SSC receive clock is - * generated from the transmit clock. - * - * For single channel data, one sample is transferred - * on the falling edge of the LRC clock. - * For two channel data, one sample is - * transferred on both edges of the LRC clock. - */ - start_event = ((channels == 1) - ? SSC_START_FALLING_RF - : SSC_START_EDGE_RF); - - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, start_event) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, 0) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, 0) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, start_event) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, 0) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output - * on the SSC TK line. - */ - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) - | SSC_BF(RCMR_STTDLY, 1) - | SSC_BF(RCMR_START, SSC_START_RISING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) - | SSC_BF(TCMR_STTDLY, 1) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_RISING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - default: - printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", - ssc_p->daifmt); - return -EINVAL; - break; - } - pr_debug("atmel_ssc_hw_params: " - "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", - rcmr, rfmr, tcmr, tfmr); - - if (!ssc_p->initialized) { - - /* Enable PMC peripheral clock for this SSC */ - pr_debug("atmel_ssc_dai: Starting clock\n"); - clk_enable(ssc_p->ssc->clk); - - /* Reset the SSC and its PDC registers */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); - - ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); - - ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0, - ssc_p->name, ssc_p); - if (ret < 0) { - printk(KERN_WARNING - "atmel_ssc_dai: request_irq failure\n"); - pr_debug("Atmel_ssc_dai: Stoping clock\n"); - clk_disable(ssc_p->ssc->clk); - return ret; - } - - ssc_p->initialized = 1; - } - - /* set SSC clock mode register */ - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); - - /* set receive clock mode and format */ - ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); - - /* set transmit clock mode and format */ - ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); - ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); - - pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n"); - return 0; -} - - -static int atmel_ssc_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct atmel_pcm_dma_params *dma_params; - int dir; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = 0; - else - dir = 1; - - dma_params = ssc_p->dma_params[dir]; - - ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); - - pr_debug("%s enabled SSC_SR=0x%08x\n", - dir ? "receive" : "transmit", - ssc_readl(ssc_p->ssc->regs, SR)); - return 0; -} - - -#ifdef CONFIG_PM -static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) -{ - struct atmel_ssc_info *ssc_p; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* Save the status register before disabling transmit and receive */ - ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); - - /* Save the current interrupt mask, then disable unmasked interrupts */ - ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); - ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); - ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); - ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); - ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); - ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); - - return 0; -} - - - -static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) -{ - struct atmel_ssc_info *ssc_p; - u32 cr; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* restore SSC register settings */ - ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); - ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); - ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); - - /* re-enable interrupts */ - ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); - - /* Re-enable recieve and transmit as appropriate */ - cr = 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; - ssc_writel(ssc_p->ssc->regs, CR, cr); - - return 0; -} -#else /* CONFIG_PM */ -# define atmel_ssc_suspend NULL -# define atmel_ssc_resume NULL -#endif /* CONFIG_PM */ - - -#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) - -#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { - { .name = "atmel-ssc0", - .id = 0, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = { - .startup = atmel_ssc_startup, - .shutdown = atmel_ssc_shutdown, - .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params, - .set_fmt = atmel_ssc_set_dai_fmt, - .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[0], - }, -#if NUM_SSC_DEVICES == 3 - { .name = "atmel-ssc1", - .id = 1, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = { - .startup = atmel_ssc_startup, - .shutdown = atmel_ssc_shutdown, - .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params, - .set_fmt = atmel_ssc_set_dai_fmt, - .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[1], - }, - { .name = "atmel-ssc2", - .id = 2, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = { - .startup = atmel_ssc_startup, - .shutdown = atmel_ssc_shutdown, - .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params, - .set_fmt = atmel_ssc_set_dai_fmt, - .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[2], - }, -#endif -}; -EXPORT_SYMBOL_GPL(atmel_ssc_dai); - -static int __devinit atmel_ssc_modinit(void) -{ - return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); -} -module_init(atmel_ssc_modinit); - -static void __exit atmel_ssc_modexit(void) -{ - snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); -} -module_exit(atmel_ssc_modexit); - -/* Module information */ -MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); -MODULE_DESCRIPTION("ATMEL SSC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h deleted file mode 100644 index a828746e8a2f..000000000000 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * atmel_ssc_dai.h - ALSA SSC interface for the Atmel SoC - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * ATMEL CORP. - * - * Based on at91-ssc.c by - * Frank Mandarino <fmandarino@endrelia.com> - * Based on pxa2xx Platform drivers by - * Liam Girdwood <liam.girdwood@wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ATMEL_SSC_DAI_H -#define _ATMEL_SSC_DAI_H - -#include <linux/types.h> -#include <linux/atmel-ssc.h> - -#include "atmel-pcm.h" - -/* SSC system clock ids */ -#define ATMEL_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ - -/* SSC divider ids */ -#define ATMEL_SSC_CMR_DIV 0 /* MCK divider for BCLK */ -#define ATMEL_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ -#define ATMEL_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ -/* - * SSC direction masks - */ -#define SSC_DIR_MASK_UNUSED 0 -#define SSC_DIR_MASK_PLAYBACK 1 -#define SSC_DIR_MASK_CAPTURE 2 - -/* - * SSC register values that Atmel left out of <linux/atmel-ssc.h>. These - * are expected to be used with SSC_BF - */ -/* START bit field values */ -#define SSC_START_CONTINUOUS 0 -#define SSC_START_TX_RX 1 -#define SSC_START_LOW_RF 2 -#define SSC_START_HIGH_RF 3 -#define SSC_START_FALLING_RF 4 -#define SSC_START_RISING_RF 5 -#define SSC_START_LEVEL_RF 6 -#define SSC_START_EDGE_RF 7 -#define SSS_START_COMPARE_0 8 - -/* CKI bit field values */ -#define SSC_CKI_FALLING 0 -#define SSC_CKI_RISING 1 - -/* CKO bit field values */ -#define SSC_CKO_NONE 0 -#define SSC_CKO_CONTINUOUS 1 -#define SSC_CKO_TRANSFER 2 - -/* CKS bit field values */ -#define SSC_CKS_DIV 0 -#define SSC_CKS_CLOCK 1 -#define SSC_CKS_PIN 2 - -/* FSEDGE bit field values */ -#define SSC_FSEDGE_POSITIVE 0 -#define SSC_FSEDGE_NEGATIVE 1 - -/* FSOS bit field values */ -#define SSC_FSOS_NONE 0 -#define SSC_FSOS_NEGATIVE 1 -#define SSC_FSOS_POSITIVE 2 -#define SSC_FSOS_LOW 3 -#define SSC_FSOS_HIGH 4 -#define SSC_FSOS_TOGGLE 5 - -#define START_DELAY 1 - -struct atmel_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - - -struct atmel_ssc_info { - char *name; - struct ssc_device *ssc; - spinlock_t lock; /* lock for dir_mask */ - unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ - unsigned short initialized; /* true if SSC has been initialized */ - unsigned short daifmt; - unsigned short cmr_div; - unsigned short tcmr_period; - unsigned short rcmr_period; - struct atmel_pcm_dma_params *dma_params[2]; - struct atmel_ssc_state ssc_state; -}; -extern struct snd_soc_dai atmel_ssc_dai[]; - -#endif /* _AT91_SSC_DAI_H */ diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c deleted file mode 100644 index 1fb59a9d3719..000000000000 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * sam9g20_wm8731 -- SoC audio for AT91SAM9G20-based - * ATMEL AT91SAM9G20ek board. - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * - * Based on ati_b1_wm8731.c by: - * Frank Mandarino <fmandarino@endrelia.com> - * Copyright 2006 Endrelia Technologies Inc. - * Based on corgi.c by: - * Copyright 2005 Wolfson Microelectronics PLC. - * Copyright 2005 Openedhand Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> - -#include <linux/atmel-ssc.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <mach/hardware.h> -#include <mach/gpio.h> - -#include "../codecs/wm8731.h" -#include "atmel-pcm.h" -#include "atmel_ssc_dai.h" - - -static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - int ret; - - /* codec system clock is supplied by PCK0, set to 12MHz */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, - 12000000, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return 0; -} - -static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - - dev_dbg(rtd->socdev->dev, "shutdown"); -} - -static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct atmel_ssc_info *ssc_p = cpu_dai->private_data; - struct ssc_device *ssc = ssc_p->ssc; - int ret; - - unsigned int rate; - int cmr_div, period; - - if (ssc == NULL) { - printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n"); - return -EINVAL; - } - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* - * The SSC clock dividers depend on the sample rate. The CMR.DIV - * field divides the system master clock MCK to drive the SSC TK - * signal which provides the codec BCLK. The TCMR.PERIOD and - * RCMR.PERIOD fields further divide the BCLK signal to drive - * the SSC TF and RF signals which provide the codec DACLRC and - * ADCLRC clocks. - * - * The dividers were determined through trial and error, where a - * CMR.DIV value is chosen such that the resulting BCLK value is - * divisible, or almost divisible, by (2 * sample rate), and then - * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. - */ - rate = params_rate(params); - - switch (rate) { - case 8000: - cmr_div = 55; /* BCLK = 133MHz/(2*55) = 1.209MHz */ - period = 74; /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */ - break; - case 11025: - cmr_div = 67; /* BCLK = 133MHz/(2*60) = 1.108MHz */ - period = 45; /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */ - break; - case 16000: - cmr_div = 63; /* BCLK = 133MHz/(2*63) = 1.055MHz */ - period = 32; /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */ - break; - case 22050: - cmr_div = 52; /* BCLK = 133MHz/(2*52) = 1.278MHz */ - period = 28; /* LRC = BCLK/(2*(28+1)) = 22049Hz */ - break; - case 32000: - cmr_div = 66; /* BCLK = 133MHz/(2*66) = 1.007MHz */ - period = 15; /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */ - break; - case 44100: - cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ - period = 25; /* LRC = BCLK/(2*(25+1)) = 44098Hz */ - break; - case 48000: - cmr_div = 33; /* BCLK = 133MHz/(2*33) = 2.015MHz */ - period = 20; /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */ - break; - case 88200: - cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ - period = 12; /* LRC = BCLK/(2*(12+1)) = 88196Hz */ - break; - case 96000: - cmr_div = 23; /* BCLK = 133MHz/(2*23) = 2.891MHz */ - period = 14; /* LRC = BCLK/(2*(14+1)) = 96376Hz */ - break; - default: - printk(KERN_WARNING "unsupported rate %d" - " on at91sam9g20ek board\n", rate); - return -EINVAL; - } - - /* set the MCK divider for BCLK */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div); - if (ret < 0) - return ret; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* set the BCLK divider for DACLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, - ATMEL_SSC_TCMR_PERIOD, period); - } else { - /* set the BCLK divider for ADCLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, - ATMEL_SSC_RCMR_PERIOD, period); - } - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops at91sam9g20ek_ops = { - .startup = at91sam9g20ek_startup, - .hw_params = at91sam9g20ek_hw_params, - .shutdown = at91sam9g20ek_shutdown, -}; - - -static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), -}; - -static const struct snd_soc_dapm_route intercon[] = { - - /* speaker connected to LHPOUT */ - {"Ext Spk", NULL, "LHPOUT"}, - - /* mic is connected to Mic Jack, with WM8731 Mic Bias */ - {"MICIN", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Int Mic"}, -}; - -/* - * Logic for a wm8731 as connected on a at91sam9g20ek board. - */ -static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) -{ - printk(KERN_DEBUG - "at91sam9g20ek_wm8731 " - ": at91sam9g20ek_wm8731_init() called\n"); - - /* Add specific widgets */ - snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets, - ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); - /* Set up specific audio path interconnects */ - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - - /* not connected */ - snd_soc_dapm_disable_pin(codec, "RLINEIN"); - snd_soc_dapm_disable_pin(codec, "LLINEIN"); - - /* always connected */ - snd_soc_dapm_enable_pin(codec, "Int Mic"); - snd_soc_dapm_enable_pin(codec, "Ext Spk"); - - snd_soc_dapm_sync(codec); - - return 0; -} - -static struct snd_soc_dai_link at91sam9g20ek_dai = { - .name = "WM8731", - .stream_name = "WM8731 PCM", - .cpu_dai = &atmel_ssc_dai[0], - .codec_dai = &wm8731_dai, - .init = at91sam9g20ek_wm8731_init, - .ops = &at91sam9g20ek_ops, -}; - -static struct snd_soc_card snd_soc_at91sam9g20ek = { - .name = "WM8731", - .platform = &atmel_soc_platform, - .dai_link = &at91sam9g20ek_dai, - .num_links = 1, -}; - -static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { - .i2c_bus = 0, - .i2c_address = 0x1b, -}; - -static struct snd_soc_device at91sam9g20ek_snd_devdata = { - .card = &snd_soc_at91sam9g20ek, - .codec_dev = &soc_codec_dev_wm8731, - .codec_data = &at91sam9g20ek_wm8731_setup, -}; - -static struct platform_device *at91sam9g20ek_snd_device; - -static int __init at91sam9g20ek_init(void) -{ - struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; - struct ssc_device *ssc = NULL; - int ret; - - /* - * Request SSC device - */ - ssc = ssc_request(0); - if (IS_ERR(ssc)) { - ret = PTR_ERR(ssc); - ssc = NULL; - goto err_ssc; - } - ssc_p->ssc = ssc; - - at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); - if (!at91sam9g20ek_snd_device) { - printk(KERN_DEBUG - "platform device allocation failed\n"); - ret = -ENOMEM; - } - - platform_set_drvdata(at91sam9g20ek_snd_device, - &at91sam9g20ek_snd_devdata); - at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev; - - ret = platform_device_add(at91sam9g20ek_snd_device); - if (ret) { - printk(KERN_DEBUG - "platform device allocation failed\n"); - platform_device_put(at91sam9g20ek_snd_device); - } - - return ret; - -err_ssc: - return ret; -} - -static void __exit at91sam9g20ek_exit(void) -{ - struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; - struct ssc_device *ssc; - - if (ssc_p != NULL) { - ssc = ssc_p->ssc; - if (ssc != NULL) - ssc_free(ssc); - ssc_p->ssc = NULL; - } - - platform_device_unregister(at91sam9g20ek_snd_device); - at91sam9g20ek_snd_device = NULL; -} - -module_init(at91sam9g20ek_init); -module_exit(at91sam9g20ek_exit); - -/* Module information */ -MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); -MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 74c823d60f91..1466d9328800 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -406,12 +406,11 @@ static int __init au1xpsc_audio_dbdma_init(void) { au1xpsc_audio_pcmdma[PCM_TX] = NULL; au1xpsc_audio_pcmdma[PCM_RX] = NULL; - return snd_soc_register_platform(&au1xpsc_soc_platform); + return 0; } static void __exit au1xpsc_audio_dbdma_exit(void) { - snd_soc_unregister_platform(&au1xpsc_soc_platform); } module_init(au1xpsc_audio_dbdma_init); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index f0e30aec7f23..57facbad6825 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -160,8 +160,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; @@ -211,7 +210,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, } static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) + int cmd) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; @@ -314,7 +313,8 @@ static void au1xpsc_ac97_remove(struct platform_device *pdev, au1xpsc_ac97_workdata = NULL; } -static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai) +static int au1xpsc_ac97_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) { /* save interesting registers and disable PSC */ au1xpsc_ac97_workdata->pm[0] = @@ -328,7 +328,8 @@ static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai) return 0; } -static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) +static int au1xpsc_ac97_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { /* restore PSC clock config */ au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, @@ -344,7 +345,7 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) struct snd_soc_dai au1xpsc_ac97_dai = { .name = "au1xpsc_ac97", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = au1xpsc_ac97_probe, .remove = au1xpsc_ac97_remove, .suspend = au1xpsc_ac97_suspend, @@ -371,12 +372,11 @@ EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); static int __init au1xpsc_ac97_init(void) { au1xpsc_ac97_workdata = NULL; - return snd_soc_register_dai(&au1xpsc_ac97_dai); + return 0; } static void __exit au1xpsc_ac97_exit(void) { - snd_soc_unregister_dai(&au1xpsc_ac97_dai); } module_init(au1xpsc_ac97_init); diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index f916de4400ed..9384702c7ebd 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -116,8 +116,7 @@ out: } static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; @@ -241,8 +240,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) return 0; } -static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; int ret, stype = SUBSTREAM_TYPE(substream); @@ -339,7 +337,8 @@ static void au1xpsc_i2s_remove(struct platform_device *pdev, au1xpsc_i2s_workdata = NULL; } -static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { /* save interesting register and disable PSC */ au1xpsc_i2s_workdata->pm[0] = @@ -353,7 +352,8 @@ static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai) return 0; } -static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { /* select I2S mode and PSC clock */ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); @@ -369,6 +369,7 @@ static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) struct snd_soc_dai au1xpsc_i2s_dai = { .name = "au1xpsc_i2s", + .type = SND_SOC_DAI_I2S, .probe = au1xpsc_i2s_probe, .remove = au1xpsc_i2s_remove, .suspend = au1xpsc_i2s_suspend, @@ -388,6 +389,8 @@ struct snd_soc_dai au1xpsc_i2s_dai = { .ops = { .trigger = au1xpsc_i2s_trigger, .hw_params = au1xpsc_i2s_hw_params, + }, + .dai_ops = { .set_fmt = au1xpsc_i2s_set_fmt, }, }; @@ -396,12 +399,11 @@ EXPORT_SYMBOL(au1xpsc_i2s_dai); static int __init au1xpsc_i2s_init(void) { au1xpsc_i2s_workdata = NULL; - return snd_soc_register_dai(&au1xpsc_i2s_dai); + return 0; } static void __exit au1xpsc_i2s_exit(void) { - snd_soc_unregister_dai(&au1xpsc_i2s_dai); } module_init(au1xpsc_i2s_init); diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c index 27683eb7905e..f75ae7f62c3d 100644 --- a/sound/soc/au1x/sample-ac97.c +++ b/sound/soc/au1x/sample-ac97.c @@ -42,14 +42,14 @@ static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { .ops = NULL, }; -static struct snd_soc_card au1xpsc_sample_ac97_machine = { +static struct snd_soc_machine au1xpsc_sample_ac97_machine = { .name = "Au1xxx PSC AC97 Audio", .dai_link = &au1xpsc_sample_ac97_dai, .num_links = 1, }; static struct snd_soc_device au1xpsc_sample_ac97_devdata = { - .card = &au1xpsc_sample_ac97_machine, + .machine = &au1xpsc_sample_ac97_machine, .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 0a2f8f9eff53..dc006206f622 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -1,6 +1,6 @@ config SND_BF5XX_I2S tristate "SoC I2S Audio for the ADI BF5xx chip" - depends on BLACKFIN + depends on BLACKFIN && SND_SOC help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in I2S @@ -13,6 +13,7 @@ config SND_BF5XX_SOC_SSM2602 select SND_BF5XX_SOC_I2S select SND_SOC_SSM2602 select I2C + select I2C_BLACKFIN_TWI help Say Y if you want to add support for SoC audio on BF527-EZKIT. @@ -34,7 +35,7 @@ config SND_BFIN_AD73311_SE config SND_BF5XX_AC97 tristate "SoC AC97 Audio for the ADI BF5xx chip" - depends on BLACKFIN + depends on BLACKFIN && SND_SOC help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in slot 16 @@ -46,7 +47,7 @@ config SND_BF5XX_AC97 properly with this driver. This driver is known to work with the Analog Devices line of AC97 codecs. -config SND_BF5XX_MMAP_SUPPORT +config SND_MMAP_SUPPORT bool "Enable MMAP Support" depends on SND_BF5XX_AC97 default y @@ -54,17 +55,9 @@ config SND_BF5XX_MMAP_SUPPORT Say y if you want AC97 driver to support mmap mode. We introduce an intermediate buffer to simulate mmap. -config SND_BF5XX_MULTICHAN_SUPPORT - bool "Enable Multichannel Support" - depends on SND_BF5XX_AC97 - default n - help - Say y if you want AC97 driver to support up to 5.1 channel audio. - this mode will consume much more memory for DMA. - config SND_BF5XX_SOC_SPORT tristate - + config SND_BF5XX_SOC_I2S tristate select SND_BF5XX_SOC_SPORT @@ -87,7 +80,7 @@ config SND_BF5XX_SPORT_NUM int "Set a SPORT for Sound chip" depends on (SND_BF5XX_I2S || SND_BF5XX_AC97) range 0 3 if BF54x - range 0 1 if !BF54x + range 0 1 if (BF53x || BF561) default 0 help Set the correct SPORT for sound chip. @@ -97,13 +90,12 @@ config SND_BF5XX_HAVE_COLD_RESET depends on SND_BF5XX_AC97 default y if BFIN548_EZKIT default n if !BFIN548_EZKIT - + config SND_BF5XX_RESET_GPIO_NUM int "Set a GPIO for cold reset" depends on SND_BF5XX_HAVE_COLD_RESET range 0 159 default 19 if BFIN548_EZKIT default 5 if BFIN537_STAMP - default 0 help Set the correct GPIO for RESET the sound chip. diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 5b27e0d9d0ec..25e50d2ea1ec 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -43,34 +43,24 @@ #include "bf5xx-ac97.h" #include "bf5xx-sport.h" -static unsigned int ac97_chan_mask[] = { - SP_FL, /* Mono */ - SP_STEREO, /* Stereo */ - SP_2DOT1, /* 2.1*/ - SP_QUAD,/*Quadraquic*/ - SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */ - SP_5DOT1, /* 5.1 */ -}; - -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; struct sport_device *sport = runtime->private_data; - unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf + - sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos * - runtime->channels, count, chan_mask); + bf5xx_pcm_to_ac97( + (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos, + (__u32 *)runtime->dma_area + sport->tx_pos, count); sport->tx_pos += runtime->period_size; if (sport->tx_pos >= runtime->buffer_size) sport->tx_pos %= runtime->buffer_size; sport->tx_delay_pos = sport->tx_pos; } else { - bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf + - sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos * - runtime->channels, count); + bf5xx_ac97_to_pcm( + (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, + (__u32 *)runtime->dma_area + sport->rx_pos, count); sport->rx_pos += runtime->period_size; if (sport->rx_pos >= runtime->buffer_size) sport->rx_pos %= runtime->buffer_size; @@ -81,7 +71,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, static void bf5xx_dma_irq(void *data) { struct snd_pcm_substream *pcm = data; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = pcm->runtime; struct sport_device *sport = runtime->private_data; bf5xx_mmap_copy(pcm, runtime->period_size); @@ -100,14 +90,17 @@ static void bf5xx_dma_irq(void *data) * The total rx/tx buffer is for ac97 frame to hold all pcm data * is 0x20000 * sizeof(struct ac97_frame) / 4. */ +#ifdef CONFIG_SND_MMAP_SUPPORT static const struct snd_pcm_hardware bf5xx_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | -#endif SNDRV_PCM_INFO_BLOCK_TRANSFER, - +#else +static const struct snd_pcm_hardware bf5xx_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, +#endif .formats = SNDRV_PCM_FMTBIT_S16_LE, .period_bytes_min = 32, .period_bytes_max = 0x10000, @@ -130,20 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = substream->runtime; - struct sport_device *sport = runtime->private_data; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - sport->once = 0; - if (runtime->dma_area) - memset(runtime->dma_area, 0, runtime->buffer_size); - memset(sport->tx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); - } else - memset(sport->rx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); -#endif + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + memset(runtime->dma_area, 0, runtime->buffer_size); snd_pcm_lib_free_pages(substream); return 0; } @@ -156,7 +139,7 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) /* An intermediate buffer is introduced for implementing mmap for * SPORT working in TMD mode(include AC97). */ -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { sport_set_tx_callback(sport, bf5xx_dma_irq, substream); sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, @@ -190,24 +173,24 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) bf5xx_mmap_copy(substream, runtime->period_size); + snd_pcm_period_elapsed(substream); sport->tx_delay_pos = 0; -#endif sport_tx_start(sport); - } else + } + else sport_rx_start(sport); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) sport->tx_pos = 0; #endif sport_tx_stop(sport); } else { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) sport->rx_pos = 0; #endif sport_rx_stop(sport); @@ -225,7 +208,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) struct sport_device *sport = runtime->private_data; unsigned int curr; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) curr = sport->tx_delay_pos; else @@ -266,7 +249,22 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) return ret; } -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +static int bf5xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + + pr_debug("%s enter\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sport->once = 0; + memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + } else + memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + + return 0; +} + +#ifdef CONFIG_SND_MMAP_SUPPORT static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -283,29 +281,32 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, void __user *buf, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; + pr_debug("%s copy pos:0x%lx count:0x%lx\n", substream->stream ? "Capture" : "Playback", pos, count); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos, - (__u16 *)buf, count, chan_mask); + bf5xx_pcm_to_ac97( + (struct ac97_frame *)runtime->dma_area + pos, + buf, count); else - bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos, - (__u16 *)buf, count); + bf5xx_ac97_to_pcm( + (struct ac97_frame *)runtime->dma_area + pos, + buf, count); return 0; } #endif struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .open = bf5xx_pcm_open, + .close = bf5xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = bf5xx_pcm_hw_params, .hw_free = bf5xx_pcm_hw_free, .prepare = bf5xx_pcm_prepare, .trigger = bf5xx_pcm_trigger, .pointer = bf5xx_pcm_pointer, -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#ifdef CONFIG_SND_MMAP_SUPPORT .mmap = bf5xx_pcm_mmap, #else .copy = bf5xx_pcm_copy, @@ -343,7 +344,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) * Need to allocate local buffer when enable * MMAP for SPORT working in TMD mode (include AC97). */ -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!sport_handle->tx_dma_buf) { sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ @@ -380,7 +381,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; int stream; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) size_t size = bf5xx_pcm_hardware.buffer_bytes_max * sizeof(struct ac97_frame) / 4; #endif @@ -394,7 +395,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) continue; dma_free_coherent(NULL, buf->bytes, buf->area, 0); buf->area = NULL; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (sport_handle->tx_dma_buf) dma_free_coherent(NULL, size, \ @@ -451,18 +452,6 @@ struct snd_soc_platform bf5xx_ac97_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform); -static int __devinit bfin_ac97_init(void) -{ - return snd_soc_register_platform(&bf5xx_ac97_soc_platform); -} -module_init(bfin_ac97_init); - -static void __exit bfin_ac97_exit(void) -{ - snd_soc_unregister_platform(&bf5xx_ac97_soc_platform); -} -module_exit(bfin_ac97_exit); - MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index ad3efeeb6d44..5e5aafb6485f 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -54,103 +54,71 @@ static int *cmd_count; static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; -static u16 sport_req[][7] = { - PIN_REQ_SPORT_0, -#ifdef PIN_REQ_SPORT_1 - PIN_REQ_SPORT_1, -#endif -#ifdef PIN_REQ_SPORT_2 - PIN_REQ_SPORT_2, -#endif -#ifdef PIN_REQ_SPORT_3 - PIN_REQ_SPORT_3, -#endif - }; - +#if defined(CONFIG_BF54x) static struct sport_param sport_params[4] = { { .dma_rx_chan = CH_SPORT0_RX, .dma_tx_chan = CH_SPORT0_TX, - .err_irq = IRQ_SPORT0_ERROR, + .err_irq = IRQ_SPORT0_ERR, .regs = (struct sport_register *)SPORT0_TCR1, }, -#ifdef PIN_REQ_SPORT_1 { .dma_rx_chan = CH_SPORT1_RX, .dma_tx_chan = CH_SPORT1_TX, - .err_irq = IRQ_SPORT1_ERROR, + .err_irq = IRQ_SPORT1_ERR, .regs = (struct sport_register *)SPORT1_TCR1, }, -#endif -#ifdef PIN_REQ_SPORT_2 { .dma_rx_chan = CH_SPORT2_RX, .dma_tx_chan = CH_SPORT2_TX, - .err_irq = IRQ_SPORT2_ERROR, + .err_irq = IRQ_SPORT2_ERR, .regs = (struct sport_register *)SPORT2_TCR1, }, -#endif -#ifdef PIN_REQ_SPORT_3 { .dma_rx_chan = CH_SPORT3_RX, .dma_tx_chan = CH_SPORT3_TX, - .err_irq = IRQ_SPORT3_ERROR, + .err_irq = IRQ_SPORT3_ERR, .regs = (struct sport_register *)SPORT3_TCR1, } -#endif }; +#else +static struct sport_param sport_params[2] = { + { + .dma_rx_chan = CH_SPORT0_RX, + .dma_tx_chan = CH_SPORT0_TX, + .err_irq = IRQ_SPORT0_ERROR, + .regs = (struct sport_register *)SPORT0_TCR1, + }, + { + .dma_rx_chan = CH_SPORT1_RX, + .dma_tx_chan = CH_SPORT1_TX, + .err_irq = IRQ_SPORT1_ERROR, + .regs = (struct sport_register *)SPORT1_TCR1, + } +}; +#endif -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, - size_t count, unsigned int chan_mask) +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ + size_t count) { while (count--) { - dst->ac97_tag = TAG_VALID; - if (chan_mask & SP_FL) { - dst->ac97_pcm_r = *src++; - dst->ac97_tag |= TAG_PCM_RIGHT; - } - if (chan_mask & SP_FR) { - dst->ac97_pcm_l = *src++; - dst->ac97_tag |= TAG_PCM_LEFT; - - } -#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) - if (chan_mask & SP_SR) { - dst->ac97_sl = *src++; - dst->ac97_tag |= TAG_PCM_SL; - } - if (chan_mask & SP_SL) { - dst->ac97_sr = *src++; - dst->ac97_tag |= TAG_PCM_SR; - } - if (chan_mask & SP_LFE) { - dst->ac97_lfe = *src++; - dst->ac97_tag |= TAG_PCM_LFE; - } - if (chan_mask & SP_FC) { - dst->ac97_center = *src++; - dst->ac97_tag |= TAG_PCM_CENTER; - } -#endif - dst++; + dst->ac97_tag = TAG_VALID | TAG_PCM; + (dst++)->ac97_pcm = *src++; } } EXPORT_SYMBOL(bf5xx_pcm_to_ac97); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ size_t count) { - while (count--) { - *(dst++) = src->ac97_pcm_l; - *(dst++) = src->ac97_pcm_r; - src++; - } + while (count--) + *(dst++) = (src++)->ac97_pcm; } EXPORT_SYMBOL(bf5xx_ac97_to_pcm); static unsigned int sport_tx_curr_frag(struct sport_device *sport) { - return sport->tx_curr_frag = sport_curr_offset_tx(sport) / + return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \ sport->tx_fragsize; } @@ -162,7 +130,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) sport_incfrag(sport, &nextfrag, 1); - nextwrite = (struct ac97_frame *)(sport->tx_buf + + nextwrite = (struct ac97_frame *)(sport->tx_buf + \ nextfrag * sport->tx_fragsize); pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); @@ -269,7 +237,8 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); #ifdef CONFIG_PM -static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) +static int bf5xx_ac97_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; @@ -284,7 +253,8 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) return 0; } -static int bf5xx_ac97_resume(struct snd_soc_dai *dai) +static int bf5xx_ac97_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { int ret; struct sport_device *sport = @@ -327,15 +297,20 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai) static int bf5xx_ac97_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { - int ret = 0; + int ret; +#if defined(CONFIG_BF54x) + u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1, + PIN_REQ_SPORT_2, PIN_REQ_SPORT_3}; +#else + u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1}; +#endif cmd_count = (int *)get_zeroed_page(GFP_KERNEL); if (cmd_count == NULL) return -ENOMEM; if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { pr_err("Requesting Peripherals failed\n"); - ret = -EFAULT; - goto peripheral_err; + return -EFAULT; } #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET @@ -343,54 +318,54 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { pr_err("Failed to request GPIO_%d for reset\n", CONFIG_SND_BF5XX_RESET_GPIO_NUM); - ret = -1; - goto gpio_err; + peripheral_free_list(&sport_req[sport_num][0]); + return -1; } gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); #endif sport_handle = sport_init(&sport_params[sport_num], 2, \ sizeof(struct ac97_frame), NULL); if (!sport_handle) { - ret = -ENODEV; - goto sport_err; + peripheral_free_list(&sport_req[sport_num][0]); +#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); +#endif + return -ENODEV; } /*SPORT works in TDM mode to simulate AC97 transfers*/ ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); if (ret) { pr_err("SPORT is busy!\n"); - ret = -EBUSY; - goto sport_config_err; + kfree(sport_handle); + peripheral_free_list(&sport_req[sport_num][0]); +#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); +#endif + return -EBUSY; } ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - ret = -EBUSY; - goto sport_config_err; + kfree(sport_handle); + peripheral_free_list(&sport_req[sport_num][0]); +#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); +#endif + return -EBUSY; } ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - ret = -EBUSY; - goto sport_config_err; - } - - return 0; - -sport_config_err: - kfree(sport_handle); -sport_err: + kfree(sport_handle); + peripheral_free_list(&sport_req[sport_num][0]); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif -gpio_err: - peripheral_free_list(&sport_req[sport_num][0]); -peripheral_err: - free_page((unsigned long)cmd_count); - cmd_count = NULL; - - return ret; + return -EBUSY; + } + return 0; } static void bf5xx_ac97_remove(struct platform_device *pdev, @@ -398,7 +373,6 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, { free_page((unsigned long)cmd_count); cmd_count = NULL; - peripheral_free_list(&sport_req[sport_num][0]); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif @@ -407,7 +381,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, struct snd_soc_dai bfin_ac97_dai = { .name = "bf5xx-ac97", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = bf5xx_ac97_probe, .remove = bf5xx_ac97_remove, .suspend = bf5xx_ac97_suspend, @@ -415,11 +389,7 @@ struct snd_soc_dai bfin_ac97_dai = { .playback = { .stream_name = "AC97 Playback", .channels_min = 2, -#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) - .channels_max = 6, -#else .channels_max = 2, -#endif .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { @@ -431,18 +401,6 @@ struct snd_soc_dai bfin_ac97_dai = { }; EXPORT_SYMBOL_GPL(bfin_ac97_dai); -static int __devinit bfin_ac97_init(void) -{ - return snd_soc_register_dai(&bfin_ac97_dai); -} -module_init(bfin_ac97_init); - -static void __exit bfin_ac97_exit(void) -{ - snd_soc_unregister_dai(&bfin_ac97_dai); -} -module_exit(bfin_ac97_exit); - MODULE_AUTHOR("Roy Huang"); MODULE_DESCRIPTION("AC97 driver for ADI Blackfin"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h index 3f2a911fe0cb..3f77cc558dc0 100644 --- a/sound/soc/blackfin/bf5xx-ac97.h +++ b/sound/soc/blackfin/bf5xx-ac97.h @@ -16,46 +16,21 @@ struct ac97_frame { u16 ac97_tag; /* slot 0 */ u16 ac97_addr; /* slot 1 */ u16 ac97_data; /* slot 2 */ - u16 ac97_pcm_l; /*slot 3:front left*/ - u16 ac97_pcm_r; /*slot 4:front left*/ -#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) - u16 ac97_mdm_l1; - u16 ac97_center; /*slot 6:center*/ - u16 ac97_sl; /*slot 7:surround left*/ - u16 ac97_sr; /*slot 8:surround right*/ - u16 ac97_lfe; /*slot 9:lfe*/ -#endif + u32 ac97_pcm; /* slot 3 and 4: left and right pcm data */ } __attribute__ ((packed)); -/* Speaker location */ -#define SP_FL 0x0001 -#define SP_FR 0x0010 -#define SP_FC 0x0002 -#define SP_LFE 0x0020 -#define SP_SL 0x0004 -#define SP_SR 0x0040 - -#define SP_STEREO (SP_FL | SP_FR) -#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE) -#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR) -#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR) - #define TAG_VALID 0x8000 #define TAG_CMD 0x6000 #define TAG_PCM_LEFT 0x1000 #define TAG_PCM_RIGHT 0x0800 -#define TAG_PCM_MDM_L1 0x0400 -#define TAG_PCM_CENTER 0x0200 -#define TAG_PCM_SL 0x0100 -#define TAG_PCM_SR 0x0080 -#define TAG_PCM_LFE 0x0040 +#define TAG_PCM (TAG_PCM_LEFT | TAG_PCM_RIGHT) extern struct snd_soc_dai bfin_ac97_dai; -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \ - size_t count, unsigned int chan_mask); +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ + size_t count); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \ +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ size_t count); #endif diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index d8f591273778..124425d22320 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -43,7 +43,7 @@ #include "bf5xx-ac97-pcm.h" #include "bf5xx-ac97.h" -static struct snd_soc_card bf5xx_board; +static struct snd_soc_machine bf5xx_board; static int bf5xx_board_startup(struct snd_pcm_substream *substream) { @@ -67,15 +67,15 @@ static struct snd_soc_dai_link bf5xx_board_dai = { .ops = &bf5xx_board_ops, }; -static struct snd_soc_card bf5xx_board = { +static struct snd_soc_machine bf5xx_board = { .name = "bf5xx-board", - .platform = &bf5xx_ac97_soc_platform, .dai_link = &bf5xx_board_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_board_snd_devdata = { - .card = &bf5xx_board, + .machine = &bf5xx_board, + .platform = &bf5xx_ac97_soc_platform, .codec_dev = &soc_codec_dev_ad1980, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 7f2a5e199075..622c9b909532 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -65,7 +65,7 @@ #define GPIO_SE CONFIG_SND_BFIN_AD73311_SE -static struct snd_soc_card bf5xx_ad73311; +static struct snd_soc_machine bf5xx_ad73311; static int snd_ad73311_startup(void) { @@ -168,7 +168,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream, params_format(params)); /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; @@ -190,16 +190,16 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai = { .ops = &bf5xx_ad73311_ops, }; -static struct snd_soc_card bf5xx_ad73311 = { +static struct snd_soc_machine bf5xx_ad73311 = { .name = "bf5xx_ad73311", - .platform = &bf5xx_i2s_soc_platform, .probe = bf5xx_probe, .dai_link = &bf5xx_ad73311_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ad73311_snd_devdata = { - .card = &bf5xx_ad73311, + .machine = &bf5xx_ad73311, + .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ad73311, }; diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index c58b12a44870..61fccf925192 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -283,18 +283,6 @@ struct snd_soc_platform bf5xx_i2s_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform); -static int __devinit bfin_i2s_init(void) -{ - return snd_soc_register_platform(&bf5xx_i2s_soc_platform); -} -module_init(bfin_i2s_init); - -static void __exit bfin_i2s_exit(void) -{ - snd_soc_unregister_platform(&bf5xx_i2s_soc_platform); -} -module_exit(bfin_i2s_exit); - MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 0d58d2b6db6a..e020c160ee44 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -132,8 +132,7 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return ret; } -static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int bf5xx_i2s_startup(struct snd_pcm_substream *substream) { pr_debug("%s enter\n", __func__); @@ -143,8 +142,7 @@ static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, } static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { int ret = 0; @@ -195,8 +193,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream) { pr_debug("%s enter\n", __func__); bf5xx_i2s.counter--; @@ -222,14 +219,16 @@ static int bf5xx_i2s_probe(struct platform_device *pdev, return 0; } -static void bf5xx_i2s_remove(struct snd_soc_dai *dai) +static void bf5xx_i2s_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); peripheral_free_list(&sport_req[sport_num][0]); } #ifdef CONFIG_PM -static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) +static int bf5xx_i2s_suspend(struct platform_device *dev, + struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; @@ -290,6 +289,7 @@ static int bf5xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai bf5xx_i2s_dai = { .name = "bf5xx-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = bf5xx_i2s_probe, .remove = bf5xx_i2s_remove, .suspend = bf5xx_i2s_suspend, @@ -307,24 +307,13 @@ struct snd_soc_dai bf5xx_i2s_dai = { .ops = { .startup = bf5xx_i2s_startup, .shutdown = bf5xx_i2s_shutdown, - .hw_params = bf5xx_i2s_hw_params, + .hw_params = bf5xx_i2s_hw_params,}, + .dai_ops = { .set_fmt = bf5xx_i2s_set_dai_fmt, }, }; EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); -static int __devinit bfin_i2s_init(void) -{ - return snd_soc_register_dai(&bfin_i2s_dai); -} -module_init(bfin_i2s_init); - -static void __exit bfin_i2s_exit(void) -{ - snd_soc_unregister_dai(&bfin_i2s_dai); -} -module_exit(bfin_i2s_exit); - /* Module information */ MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("I2S driver for ADI Blackfin"); diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index 2e63dea73e9c..fcadcc081f7f 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -116,7 +116,7 @@ struct sport_device { void *err_data; unsigned char *tx_dma_buf; unsigned char *rx_dma_buf; -#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT +#ifdef CONFIG_SND_MMAP_SUPPORT dma_addr_t tx_dma_phy; dma_addr_t rx_dma_phy; int tx_pos;/*pcm sample count*/ diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index bc0cdded7116..e15f67fd7769 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -44,7 +44,7 @@ #include "bf5xx-i2s-pcm.h" #include "bf5xx-i2s.h" -static struct snd_soc_card bf5xx_ssm2602; +static struct snd_soc_machine bf5xx_ssm2602; static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream) { @@ -92,17 +92,17 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, */ /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; - ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; @@ -135,15 +135,15 @@ static struct ssm2602_setup_data bf5xx_ssm2602_setup = { .i2c_address = 0x1b, }; -static struct snd_soc_card bf5xx_ssm2602 = { +static struct snd_soc_machine bf5xx_ssm2602 = { .name = "bf5xx_ssm2602", - .platform = &bf5xx_i2s_soc_platform, .dai_link = &bf5xx_ssm2602_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { - .card = &bf5xx_ssm2602, + .machine = &bf5xx_ssm2602, + .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ssm2602, .codec_data = &bf5xx_ssm2602_setup, }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf68052d6924..38a0e3b620a7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,39 +1,31 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" - select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS - select SND_SOC_AD1980 if SND_SOC_AC97_BUS - select SND_SOC_AD73311 if I2C - select SND_SOC_AK4535 if I2C - select SND_SOC_CS4270 if I2C - select SND_SOC_PCM3008 - select SND_SOC_SSM2602 if I2C - select SND_SOC_TLV320AIC23 if I2C - select SND_SOC_TLV320AIC26 if SPI_MASTER - select SND_SOC_TLV320AIC3X if I2C - select SND_SOC_TWL4030 if TWL4030_CORE - select SND_SOC_UDA134X - select SND_SOC_UDA1380 if I2C - select SND_SOC_WM8510 if (I2C || SPI_MASTER) - select SND_SOC_WM8580 if I2C - select SND_SOC_WM8728 if (I2C || SPI_MASTER) - select SND_SOC_WM8731 if (I2C || SPI_MASTER) - select SND_SOC_WM8750 if (I2C || SPI_MASTER) - select SND_SOC_WM8753 if (I2C || SPI_MASTER) - select SND_SOC_WM8900 if I2C - select SND_SOC_WM8903 if I2C - select SND_SOC_WM8971 if I2C - select SND_SOC_WM8990 if I2C - select SND_SOC_WM9712 if SND_SOC_AC97_BUS - select SND_SOC_WM9713 if SND_SOC_AC97_BUS + depends on I2C + select SPI + select SPI_MASTER + select SND_SOC_AD73311 + select SND_SOC_AK4535 + select SND_SOC_CS4270 + select SND_SOC_SSM2602 + select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC26 + select SND_SOC_TLV320AIC3X + select SND_SOC_UDA1380 + select SND_SOC_WM8510 + select SND_SOC_WM8580 + select SND_SOC_WM8731 + select SND_SOC_WM8750 + select SND_SOC_WM8753 + select SND_SOC_WM8900 + select SND_SOC_WM8903 + select SND_SOC_WM8971 + select SND_SOC_WM8990 help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine driver. Selecting this option will allow these drivers to be built without an explicit machine driver for test and development purposes. - Support for the bus types used to access the codecs to be built must - be selected separately. - If unsure select "N". @@ -68,12 +60,6 @@ config SND_SOC_CS4270_VD33_ERRATA bool depends on SND_SOC_CS4270 -config SND_SOC_L3 - tristate - -config SND_SOC_PCM3008 - tristate - config SND_SOC_SSM2602 tristate @@ -89,14 +75,6 @@ config SND_SOC_TLV320AIC3X tristate depends on I2C -config SND_SOC_TWL4030 - tristate - depends on TWL4030_CORE - -config SND_SOC_UDA134X - tristate - select SND_SOC_L3 - config SND_SOC_UDA1380 tristate @@ -106,9 +84,6 @@ config SND_SOC_WM8510 config SND_SOC_WM8580 tristate -config SND_SOC_WM8728 - tristate - config SND_SOC_WM8731 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9a20fddd09c7..90f0a585fc70 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,18 +3,13 @@ snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o -snd-soc-l3-objs := l3.o -snd-soc-pcm3008-objs := pcm3008.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o -snd-soc-twl4030-objs := twl4030.o -snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o -snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o @@ -30,18 +25,13 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o -obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o -obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o -obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o -obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o -obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index fb53e6511af2..bd1ebdc6c86c 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -24,8 +24,7 @@ #define AC97_VERSION "0.6" -static int ac97_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -43,7 +42,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai ac97_dai = { .name = "AC97 HiFi", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .playback = { .stream_name = "AC97 Playback", .channels_min = 1, @@ -114,7 +113,7 @@ static int ac97_soc_probe(struct platform_device *pdev) if (ret < 0) goto bus_err; - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) goto bus_err; return 0; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 73fdbb4d4a3d..1397b8e06c0b 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -85,9 +85,6 @@ SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), -SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1), -SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1), - SOC_ENUM("Capture Source", ad1980_cap_src), SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), @@ -145,11 +142,10 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, struct snd_soc_dai ad1980_dai = { .name = "AC97", - .ac97_control = 1, .playback = { .stream_name = "Playback", .channels_min = 2, - .channels_max = 6, + .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { @@ -196,7 +192,6 @@ static int ad1980_soc_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0; u16 vendor_id2; - u16 ext_status; printk(KERN_INFO "AD1980 SoC Audio Codec\n"); @@ -239,7 +234,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) ret = ad1980_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); + printk(KERN_ERR "AC97 link error\n"); goto reset_err; } @@ -258,19 +253,12 @@ static int ad1980_soc_probe(struct platform_device *pdev) "supported\n"); } - /* unmute captures and playbacks volume */ - ac97_write(codec, AC97_MASTER, 0x0000); - ac97_write(codec, AC97_PCM, 0x0000); - ac97_write(codec, AC97_REC_GAIN, 0x0000); - ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); - ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); - - /*power on LFE/CENTER/Surround DACs*/ - ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); + ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */ + ac97_write(codec, AC97_PCM, 0x0000); /* unmute PCM out volume */ + ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */ ad1980_add_controls(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index e32f55034e64..37af8607b00a 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -8,10 +8,14 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. + * + * Revision history + * 25th Sep 2008 Initial version. */ #include <linux/init.h> #include <linux/module.h> +#include <linux/version.h> #include <linux/kernel.h> #include <linux/device.h> #include <sound/core.h> @@ -64,7 +68,7 @@ static int ad73311_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "ad73311: failed to register card\n"); goto register_err; @@ -98,18 +102,6 @@ struct snd_soc_codec_device soc_codec_dev_ad73311 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); -static int __devinit ad73311_init(void) -{ - return snd_soc_register_dai(&ad73311_dai); -} -module_init(ad73311_init); - -static void __exit ad73311_exit(void) -{ - snd_soc_unregister_dai(&ad73311_dai); -} -module_exit(ad73311_exit); - MODULE_DESCRIPTION("ASoC ad73311 driver"); MODULE_AUTHOR("Cliff Cai "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 94148fba9119..2a89b5888e11 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -339,8 +339,7 @@ static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, } static int ak4535_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -452,6 +451,8 @@ struct snd_soc_dai ak4535_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .hw_params = ak4535_hw_params, + }, + .dai_ops = { .set_fmt = ak4535_set_dai_fmt, .digital_mute = ak4535_mute, .set_sysclk = ak4535_set_dai_sysclk, @@ -512,7 +513,7 @@ static int ak4535_init(struct snd_soc_device *socdev) ak4535_add_controls(codec); ak4535_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "ak4535: failed to register card\n"); goto card_err; @@ -688,18 +689,6 @@ struct snd_soc_codec_device soc_codec_dev_ak4535 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); -static int __devinit ak4535_modinit(void) -{ - return snd_soc_register_dai(&ak4535_dai); -} -module_init(ak4535_modinit); - -static void __exit ak4535_exit(void) -{ - snd_soc_unregister_dai(&ak4535_dai); -} -module_exit(ak4535_exit); - MODULE_DESCRIPTION("Soc AK4535 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 73aaf249d782..0bbd94501d7e 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -360,14 +360,13 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, /* * Program the CS4270 with the given hardware parameters. * - * The .ops functions are used to provide board-specific data, like + * The .dai_ops functions are used to provide board-specific data, like * input frequencies, to this driver. This function takes that information, * combines it with the hardware parameters provided, and programs the * hardware accordingly. */ static int cs4270_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -451,19 +450,6 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, return ret; } - /* Disable automatic volume control. It's enabled by default, and - * it causes volume change commands to be delayed, sometimes until - * after playback has started. - */ - - reg = cs4270_read_reg_cache(codec, CS4270_TRANS); - reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); - ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); - if (ret < 0) { - printk(KERN_ERR "I2C write failed\n"); - return ret; - } - /* Thaw and power-up the codec */ ret = snd_soc_write(codec, CS4270_PWRCTL, 0); @@ -711,10 +697,10 @@ static int cs4270_probe(struct platform_device *pdev) if (codec->control_data) { /* Initialize codec ops */ cs4270_dai.ops.hw_params = cs4270_hw_params; - cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk; - cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt; + cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk; + cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt; #ifdef CONFIG_SND_SOC_CS4270_HWMUTE - cs4270_dai.ops.digital_mute = cs4270_mute; + cs4270_dai.dai_ops.digital_mute = cs4270_mute; #endif } else printk(KERN_INFO "cs4270: no I2C device found, " @@ -723,7 +709,7 @@ static int cs4270_probe(struct platform_device *pdev) printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); #endif - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "cs4270: failed to register card\n"); goto error_del_driver; @@ -774,18 +760,6 @@ struct snd_soc_codec_device soc_codec_device_cs4270 = { }; EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); -static int __devinit cs4270_init(void) -{ - return snd_soc_register_dai(&cs4270_dai); -} -module_init(cs4270_init); - -static void __exit cs4270_exit(void) -{ - snd_soc_unregister_dai(&cs4270_dai); -} -module_exit(cs4270_exit); - MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c deleted file mode 100644 index 5353af58862c..000000000000 --- a/sound/soc/codecs/l3.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * L3 code - * - * Copyright (C) 2008, Christian Pellegrin <chripell@evolware.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * - * based on: - * - * L3 bus algorithm module. - * - * Copyright (C) 2001 Russell King, All Rights Reserved. - * - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> - -#include <sound/l3.h> - -/* - * Send one byte of data to the chip. Data is latched into the chip on - * the rising edge of the clock. - */ -static void sendbyte(struct l3_pins *adap, unsigned int byte) -{ - int i; - - for (i = 0; i < 8; i++) { - adap->setclk(0); - udelay(adap->data_hold); - adap->setdat(byte & 1); - udelay(adap->data_setup); - adap->setclk(1); - udelay(adap->clock_high); - byte >>= 1; - } -} - -/* - * Send a set of bytes to the chip. We need to pulse the MODE line - * between each byte, but never at the start nor at the end of the - * transfer. - */ -static void sendbytes(struct l3_pins *adap, const u8 *buf, - int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (i) { - udelay(adap->mode_hold); - adap->setmode(0); - udelay(adap->mode); - } - adap->setmode(1); - udelay(adap->mode_setup); - sendbyte(adap, buf[i]); - } -} - -int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) -{ - adap->setclk(1); - adap->setdat(1); - adap->setmode(1); - udelay(adap->mode); - - adap->setmode(0); - udelay(adap->mode_setup); - sendbyte(adap, addr); - udelay(adap->mode_hold); - - sendbytes(adap, data, len); - - adap->setclk(1); - adap->setdat(1); - adap->setmode(0); - - return len; -} -EXPORT_SYMBOL_GPL(l3_write); - -MODULE_DESCRIPTION("L3 bit-banging driver"); -MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c deleted file mode 100644 index f333e88ee255..000000000000 --- a/sound/soc/codecs/pcm3008.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * ALSA Soc PCM3008 codec support - * - * Author: Hugo Villeneuve - * Copyright (C) 2008 Lyrtech inc - * - * Based on AC97 Soc codec, original copyright follow: - * Copyright 2005 Wolfson Microelectronics PLC. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Generic PCM3008 support. - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/gpio.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/soc.h> - -#include "pcm3008.h" - -#define PCM3008_VERSION "0.2" - -#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) - -struct snd_soc_dai pcm3008_dai = { - .name = "PCM3008 HiFi", - .playback = { - .stream_name = "PCM3008 Playback", - .channels_min = 1, - .channels_max = 2, - .rates = PCM3008_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "PCM3008 Capture", - .channels_min = 1, - .channels_max = 2, - .rates = PCM3008_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}; -EXPORT_SYMBOL_GPL(pcm3008_dai); - -static void pcm3008_gpio_free(struct pcm3008_setup_data *setup) -{ - gpio_free(setup->dem0_pin); - gpio_free(setup->dem1_pin); - gpio_free(setup->pdad_pin); - gpio_free(setup->pdda_pin); -} - -static int pcm3008_soc_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - struct pcm3008_setup_data *setup = socdev->codec_data; - int ret = 0; - - printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); - - socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (!socdev->codec) - return -ENOMEM; - - codec = socdev->codec; - mutex_init(&codec->mutex); - - codec->name = "PCM3008"; - codec->owner = THIS_MODULE; - codec->dai = &pcm3008_dai; - codec->num_dai = 1; - codec->write = NULL; - codec->read = NULL; - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - /* Register PCMs. */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "pcm3008: failed to create pcms\n"); - goto pcm_err; - } - - /* Register Card. */ - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "pcm3008: failed to register card\n"); - goto card_err; - } - - /* DEM1 DEM0 DE-EMPHASIS_MODE - * Low Low De-emphasis 44.1 kHz ON - * Low High De-emphasis OFF - * High Low De-emphasis 48 kHz ON - * High High De-emphasis 32 kHz ON - */ - - /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ - ret = gpio_request(setup->dem0_pin, "codec_dem0"); - if (ret == 0) - ret = gpio_direction_output(setup->dem0_pin, 1); - if (ret != 0) - goto gpio_err; - - /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ - ret = gpio_request(setup->dem1_pin, "codec_dem1"); - if (ret == 0) - ret = gpio_direction_output(setup->dem1_pin, 0); - if (ret != 0) - goto gpio_err; - - /* Configure PDAD GPIO. */ - ret = gpio_request(setup->pdad_pin, "codec_pdad"); - if (ret == 0) - ret = gpio_direction_output(setup->pdad_pin, 1); - if (ret != 0) - goto gpio_err; - - /* Configure PDDA GPIO. */ - ret = gpio_request(setup->pdda_pin, "codec_pdda"); - if (ret == 0) - ret = gpio_direction_output(setup->pdda_pin, 1); - if (ret != 0) - goto gpio_err; - - return ret; - -gpio_err: - pcm3008_gpio_free(setup); -card_err: - snd_soc_free_pcms(socdev); -pcm_err: - kfree(socdev->codec); - - return ret; -} - -static int pcm3008_soc_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - struct pcm3008_setup_data *setup = socdev->codec_data; - - if (!codec) - return 0; - - pcm3008_gpio_free(setup); - snd_soc_free_pcms(socdev); - kfree(socdev->codec); - - return 0; -} - -#ifdef CONFIG_PM -static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct pcm3008_setup_data *setup = socdev->codec_data; - - gpio_set_value(setup->pdad_pin, 0); - gpio_set_value(setup->pdda_pin, 0); - - return 0; -} - -static int pcm3008_soc_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct pcm3008_setup_data *setup = socdev->codec_data; - - gpio_set_value(setup->pdad_pin, 1); - gpio_set_value(setup->pdda_pin, 1); - - return 0; -} -#else -#define pcm3008_soc_suspend NULL -#define pcm3008_soc_resume NULL -#endif - -struct snd_soc_codec_device soc_codec_dev_pcm3008 = { - .probe = pcm3008_soc_probe, - .remove = pcm3008_soc_remove, - .suspend = pcm3008_soc_suspend, - .resume = pcm3008_soc_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); - -static int __devinit pcm3008_init(void) -{ - return snd_soc_register_dai(&pcm3008_dai); -} -module_init(pcm3008_init); - -static void __exit pcm3008_exit(void) -{ - snd_soc_unregister_dai(&pcm3008_dai); -} -module_exit(pcm3008_exit); - -MODULE_DESCRIPTION("Soc PCM3008 driver"); -MODULE_AUTHOR("Hugo Villeneuve"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h deleted file mode 100644 index d04e87d3c060..000000000000 --- a/sound/soc/codecs/pcm3008.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * PCM3008 ALSA SoC Layer - * - * Author: Hugo Villeneuve - * Copyright (C) 2008 Lyrtech inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_SND_SOC_PCM3008_H -#define __LINUX_SND_SOC_PCM3008_H - -struct pcm3008_setup_data { - unsigned dem0_pin; - unsigned dem1_pin; - unsigned pdad_pin; - unsigned pdda_pin; -}; - -extern struct snd_soc_codec_device soc_codec_dev_pcm3008; -extern struct snd_soc_dai pcm3008_dai; - -#endif diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 77fdcb4b9a1b..44ef0dacd564 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -285,23 +285,16 @@ static inline int get_coeff(int mclk, int rate) } static int ssm2602_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { u16 srate; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; - struct i2c_client *i2c = codec->control_data; u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; int i = get_coeff(ssm2602->sysclk, params_rate(params)); - if (substream == ssm2602->slave_substream) { - dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); - return 0; - } - /*no match is found*/ if (i == ARRAY_SIZE(coeff_div)) return -EINVAL; @@ -331,26 +324,19 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, return 0; } -static int ssm2602_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ssm2602_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; - struct i2c_client *i2c = codec->control_data; struct snd_pcm_runtime *master_runtime; /* The DAI has shared clocks so if we already have a playback or * capture going then constrain this substream to match it. - * TODO: the ssm2602 allows pairs of non-matching PB/REC rates */ if (ssm2602->master_substream) { master_runtime = ssm2602->master_substream->runtime; - dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", - master_runtime->sample_bits, - master_runtime->rate); - snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, master_runtime->rate, @@ -368,8 +354,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, return 0; } -static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -380,21 +365,14 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, return 0; } -static void ssm2602_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void ssm2602_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - struct ssm2602_priv *ssm2602 = codec->private_data; /* deactivate */ if (!codec->active) ssm2602_write(codec, SSM2602_ACTIVE, 0); - - if (ssm2602->master_substream == substream) - ssm2602->master_substream = ssm2602->slave_substream; - - ssm2602->slave_substream = NULL; } static int ssm2602_mute(struct snd_soc_dai *dai, int mute) @@ -518,9 +496,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000) -#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - struct snd_soc_dai ssm2602_dai = { .name = "SSM2602", .playback = { @@ -528,18 +503,20 @@ struct snd_soc_dai ssm2602_dai = { .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SSM2602_FORMATS,}, + .formats = SNDRV_PCM_FMTBIT_S32_LE,}, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SSM2602_FORMATS,}, + .formats = SNDRV_PCM_FMTBIT_S32_LE,}, .ops = { .startup = ssm2602_startup, .prepare = ssm2602_pcm_prepare, .hw_params = ssm2602_hw_params, .shutdown = ssm2602_shutdown, + }, + .dai_ops = { .digital_mute = ssm2602_mute, .set_sysclk = ssm2602_set_dai_sysclk, .set_fmt = ssm2602_set_dai_fmt, @@ -624,7 +601,7 @@ static int ssm2602_init(struct snd_soc_device *socdev) ssm2602_add_controls(codec); ssm2602_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { pr_err("ssm2602: failed to register card\n"); goto card_err; @@ -793,18 +770,6 @@ struct snd_soc_codec_device soc_codec_dev_ssm2602 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); -static int __devinit ssm2602_modinit(void) -{ - return snd_soc_register_dai(&ssm2602_dai); -} -module_init(ssm2602_modinit); - -static void __exit ssm2602_exit(void) -{ - snd_soc_unregister_dai(&ssm2602_dai); -} -module_exit(ssm2602_exit); - MODULE_DESCRIPTION("ASoC ssm2602 driver"); MODULE_AUTHOR("Cliff Cai"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index eac449b92bd5..44308dac9e18 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -37,6 +37,12 @@ #define AIC23_VERSION "0.1" +struct tlv320aic23_srate_reg_info { + u32 sample_rate; + u8 control; /* SR3, SR2, SR1, SR0 and BOSR */ + u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */ +}; + /* * AIC23 register cache */ @@ -255,156 +261,20 @@ static const struct snd_soc_dapm_route intercon[] = { }; -/* AIC23 driver data */ -struct aic23 { - struct snd_soc_codec codec; - int mclk; - int requested_adc; - int requested_dac; -}; - -/* - * Common Crystals used - * 11.2896 Mhz /128 = *88.2k /192 = 58.8k - * 12.0000 Mhz /125 = *96k /136 = 88.235K - * 12.2880 Mhz /128 = *96k /192 = 64k - * 16.9344 Mhz /128 = 132.3k /192 = *88.2k - * 18.4320 Mhz /128 = 144k /192 = *96k - */ - -/* - * Normal BOSR 0-256/2 = 128, 1-384/2 = 192 - * USB BOSR 0-250/2 = 125, 1-272/2 = 136 - */ -static const int bosr_usb_divisor_table[] = { - 128, 125, 192, 136 -}; -#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7)) -#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11) | (1<<15)) -static const unsigned short sr_valid_mask[] = { - LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 0*/ - LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/ - LOWER_GROUP, /* Usb, bosr - 0*/ - UPPER_GROUP, /* Usb, bosr - 1*/ -}; -/* - * Every divisor is a factor of 11*12 - */ -#define SR_MULT (11*12) -#define A(x) (x) ? (SR_MULT/x) : 0 -static const unsigned char sr_adc_mult_table[] = { - A(2), A(2), A(12), A(12), A(0), A(0), A(3), A(1), - A(2), A(2), A(11), A(11), A(0), A(0), A(0), A(1) -}; -static const unsigned char sr_dac_mult_table[] = { - A(2), A(12), A(2), A(12), A(0), A(0), A(3), A(1), - A(2), A(11), A(2), A(11), A(0), A(0), A(0), A(1) +/* tlv320aic23 related */ +static const struct tlv320aic23_srate_reg_info srate_reg_info[] = { + {4000, 0x06, 1}, /* 4000 */ + {8000, 0x06, 0}, /* 8000 */ + {16000, 0x0C, 1}, /* 16000 */ + {22050, 0x11, 1}, /* 22050 */ + {24000, 0x00, 1}, /* 24000 */ + {32000, 0x0C, 0}, /* 32000 */ + {44100, 0x11, 0}, /* 44100 */ + {48000, 0x00, 0}, /* 48000 */ + {88200, 0x1F, 0}, /* 88200 */ + {96000, 0x0E, 0}, /* 96000 */ }; -static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc, - int dac, int dac_l, int dac_h, int need_dac) -{ - if ((adc >= adc_l) && (adc <= adc_h) && - (dac >= dac_l) && (dac <= dac_h)) { - int diff_adc = need_adc - adc; - int diff_dac = need_dac - dac; - return abs(diff_adc) + abs(diff_dac); - } - return UINT_MAX; -} - -static int find_rate(int mclk, u32 need_adc, u32 need_dac) -{ - int i, j; - int best_i = -1; - int best_j = -1; - int best_div = 0; - unsigned best_score = UINT_MAX; - int adc_l, adc_h, dac_l, dac_h; - - need_adc *= SR_MULT; - need_dac *= SR_MULT; - /* - * rates given are +/- 1/32 - */ - adc_l = need_adc - (need_adc >> 5); - adc_h = need_adc + (need_adc >> 5); - dac_l = need_dac - (need_dac >> 5); - dac_h = need_dac + (need_dac >> 5); - for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) { - int base = mclk / bosr_usb_divisor_table[i]; - int mask = sr_valid_mask[i]; - for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table); - j++, mask >>= 1) { - int adc; - int dac; - int score; - if ((mask & 1) == 0) - continue; - adc = base * sr_adc_mult_table[j]; - dac = base * sr_dac_mult_table[j]; - score = get_score(adc, adc_l, adc_h, need_adc, - dac, dac_l, dac_h, need_dac); - if (best_score > score) { - best_score = score; - best_i = i; - best_j = j; - best_div = 0; - } - score = get_score((adc >> 1), adc_l, adc_h, need_adc, - (dac >> 1), dac_l, dac_h, need_dac); - /* prefer to have a /2 */ - if ((score != UINT_MAX) && (best_score >= score)) { - best_score = score; - best_i = i; - best_j = j; - best_div = 1; - } - } - } - return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT); -} - -#ifdef DEBUG -static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, - u32 *sample_rate_adc, u32 *sample_rate_dac) -{ - int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE); - int sr = (src >> 2) & 0x0f; - int val = (mclk / bosr_usb_divisor_table[src & 3]); - int adc = (val * sr_adc_mult_table[sr]) / SR_MULT; - int dac = (val * sr_dac_mult_table[sr]) / SR_MULT; - if (src & TLV320AIC23_CLKIN_HALF) { - adc >>= 1; - dac >>= 1; - } - *sample_rate_adc = adc; - *sample_rate_dac = dac; -} -#endif - -static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, - u32 sample_rate_adc, u32 sample_rate_dac) -{ - /* Search for the right sample rate */ - int data = find_rate(mclk, sample_rate_adc, sample_rate_dac); - if (data < 0) { - printk(KERN_ERR "%s:Invalid rate %u,%u requested\n", - __func__, sample_rate_adc, sample_rate_dac); - return -EINVAL; - } - tlv320aic23_write(codec, TLV320AIC23_SRATE, data); -#ifdef DEBUG - { - u32 adc, dac; - get_current_sample_rates(codec, mclk, &adc, &dac); - printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n", - adc, dac, data); - } -#endif - return 0; -} - static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) { snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, @@ -418,36 +288,32 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) } static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 iface_reg; - int ret; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); - u32 sample_rate_adc = aic23->requested_adc; - u32 sample_rate_dac = aic23->requested_dac; - u32 sample_rate = params_rate(params); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - aic23->requested_dac = sample_rate_dac = sample_rate; - if (!sample_rate_adc) - sample_rate_adc = sample_rate; - } else { - aic23->requested_adc = sample_rate_adc = sample_rate; - if (!sample_rate_dac) - sample_rate_dac = sample_rate; - } - ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc, - sample_rate_dac); - if (ret < 0) - return ret; + u16 iface_reg, data; + u8 count = 0; iface_reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2); + + /* Search for the right sample rate */ + /* Verify what happens if the rate is not supported + * now it goes to 96Khz */ + while ((srate_reg_info[count].sample_rate != params_rate(params)) && + (count < ARRAY_SIZE(srate_reg_info))) { + count++; + } + + data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) | + (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) | + TLV320AIC23_USB_CLK_ON; + + tlv320aic23_write(codec, TLV320AIC23_SRATE, data); + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; @@ -466,8 +332,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, return 0; } -static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -479,23 +344,17 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, return 0; } -static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); /* deactivate */ if (!codec->active) { udelay(50); tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - aic23->requested_dac = 0; - else - aic23->requested_adc = 0; } static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute) @@ -563,9 +422,12 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); - aic23->mclk = freq; - return 0; + + switch (freq) { + case 12000000: + return 0; + } + return -EINVAL; } static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, @@ -616,10 +478,12 @@ struct snd_soc_dai tlv320aic23_dai = { .prepare = tlv320aic23_pcm_prepare, .hw_params = tlv320aic23_hw_params, .shutdown = tlv320aic23_shutdown, - .digital_mute = tlv320aic23_mute, - .set_fmt = tlv320aic23_set_dai_fmt, - .set_sysclk = tlv320aic23_set_dai_sysclk, - } + }, + .dai_ops = { + .digital_mute = tlv320aic23_mute, + .set_fmt = tlv320aic23_set_dai_fmt, + .set_sysclk = tlv320aic23_set_dai_sysclk, + } }; EXPORT_SYMBOL_GPL(tlv320aic23_dai); @@ -720,7 +584,7 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) tlv320aic23_add_controls(codec); tlv320aic23_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "tlv320aic23: failed to register card\n"); goto card_err; @@ -795,15 +659,14 @@ static int tlv320aic23_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec; - struct aic23 *aic23; int ret = 0; printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); - aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL); - if (aic23 == NULL) + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) return -ENOMEM; - codec = &aic23->codec; + socdev->codec = codec; mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); @@ -824,7 +687,6 @@ static int tlv320aic23_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); if (codec->control_data) tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); @@ -835,7 +697,7 @@ static int tlv320aic23_remove(struct platform_device *pdev) i2c_del_driver(&tlv320aic23_i2c_driver); #endif kfree(codec->reg_cache); - kfree(aic23); + kfree(codec); return 0; } @@ -847,18 +709,6 @@ struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); -static int __devinit tlv320aic23_modinit(void) -{ - return snd_soc_register_dai(&tlv320aic23_dai); -} -module_init(tlv320aic23_modinit); - -static void __exit tlv320aic23_exit(void) -{ - snd_soc_unregister_dai(&tlv320aic23_dai); -} -module_exit(tlv320aic23_exit); - MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 29f2f1a017fd..bed8a9e63ddc 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -125,8 +125,7 @@ static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, * Digital Audio Interface Operations */ static int aic26_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -288,6 +287,8 @@ struct snd_soc_dai aic26_dai = { }, .ops = { .hw_params = aic26_hw_params, + }, + .dai_ops = { .digital_mute = aic26_mute, .set_sysclk = aic26_set_sysclk, .set_fmt = aic26_set_fmt, @@ -359,7 +360,7 @@ static int aic26_probe(struct platform_device *pdev) /* CODEC is setup, we can register the card now */ dev_dbg(&pdev->dev, "Registering card\n"); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { dev_err(&pdev->dev, "aic26: failed to register card\n"); goto card_err; @@ -426,7 +427,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); static int aic26_spi_probe(struct spi_device *spi) { struct aic26 *aic26; - int ret, i, reg; + int rc, i, reg; dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n"); @@ -456,14 +457,6 @@ static int aic26_spi_probe(struct spi_device *spi) aic26->codec.reg_cache_size = AIC26_NUM_REGS; aic26->codec.reg_cache = aic26->reg_cache; - aic26_dai.dev = &spi->dev; - ret = snd_soc_register_dai(&aic26_dai); - if (ret != 0) { - dev_err(&spi->dev, "Failed to register DAI: %d\n", ret); - kfree(aic26); - return ret; - } - /* Reset the codec to power on defaults */ aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00); @@ -482,8 +475,8 @@ static int aic26_spi_probe(struct spi_device *spi) /* Register the sysfs files for debugging */ /* Create SysFS files */ - ret = device_create_file(&spi->dev, &dev_attr_keyclick); - if (ret) + rc = device_create_file(&spi->dev, &dev_attr_keyclick); + if (rc) dev_info(&spi->dev, "error creating sysfs files\n"); #if defined(CONFIG_SND_SOC_OF_SIMPLE) @@ -500,7 +493,6 @@ static int aic26_spi_remove(struct spi_device *spi) { struct aic26 *aic26 = dev_get_drvdata(&spi->dev); - snd_soc_unregister_dai(&aic26_dai); kfree(aic26); return 0; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index ccd575961869..cff276ee261e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -253,17 +253,11 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, 0, 0x7f, 1), - SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), - SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL, - DACR1_2_LLOPM_VOL, 0, 0x7f, 1), - SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, - 0, 0x7f, 1), - SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL, - 0, 0x7f, 1), - SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, - LINE2R_2_LLOPM_VOL, 0, 0x7f, 1), - SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL, + SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, + 0x01, 0), + SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, + PGAR_2_RLOPM_VOL, 0, 0x7f, 1), + SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, @@ -278,12 +272,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPROUT_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL, + SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, 0, 0x7f, 1), - SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, - 0, 0x7f, 1), - SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL, - 0, 0x7f, 1), SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), @@ -291,10 +281,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, 0x01, 0), - SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, - 0, 0x7f, 1), - SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL, - 0, 0x7f, 1), + SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, + PGAR_2_HPRCOM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), @@ -345,8 +333,7 @@ SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); /* Left DAC_L1 Mixer */ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), @@ -354,8 +341,7 @@ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { /* Right DAC_R1 Mixer */ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), @@ -364,18 +350,14 @@ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { /* Left PGA Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1), }; /* Right PGA Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), }; @@ -397,42 +379,34 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); /* Left PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), }; /* Right PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), }; /* Left Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), }; /* Right Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), }; static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { @@ -465,26 +439,22 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Mono Output */ SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), - /* Inputs to Left ADC */ + /* Left Inputs to Left ADC */ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_left_pga_mixer_controls[0], ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1_mux_controls), - SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line2_mux_controls), - /* Inputs to Right ADC */ + /* Right Inputs to Right ADC */ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", LINE1R_2_RADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_right_pga_mixer_controls[0], ARRAY_SIZE(aic3x_right_pga_mixer_controls)), - SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, @@ -561,8 +531,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left DAC Mux", "DAC_L2", "Left DAC"}, {"Left DAC Mux", "DAC_L3", "Left DAC"}, - {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"}, - {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"}, + {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, @@ -588,8 +557,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right DAC Mux", "DAC_R2", "Right DAC"}, {"Right DAC Mux", "DAC_R3", "Right DAC"}, - {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"}, - {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"}, + {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, @@ -624,10 +592,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left Line2L Mux", "differential", "LINE2L"}, {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, - {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"}, {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, - {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Left ADC", NULL, "Left PGA Mixer"}, {"Left ADC", NULL, "GPIO1 dmic modclk"}, @@ -639,23 +605,18 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right Line2R Mux", "single-ended", "LINE2R"}, {"Right Line2R Mux", "differential", "LINE2R"}, - {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"}, {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, - {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Right ADC", NULL, "Right PGA Mixer"}, {"Right ADC", NULL, "GPIO1 dmic modclk"}, /* Left PGA Bypass */ - {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, @@ -666,13 +627,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, /* Right PGA Bypass */ - {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"}, {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"}, {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, @@ -685,11 +643,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, /* Left Line2 Bypass */ - {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, @@ -700,11 +657,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, /* Right Line2 Bypass */ - {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"}, {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, @@ -738,8 +694,7 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) } static int aic3x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1026,41 +981,14 @@ int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) } EXPORT_SYMBOL_GPL(aic3x_get_gpio); -void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, - int headset_debounce, int button_debounce) -{ - u8 val; - - val = ((detect & AIC3X_HEADSET_DETECT_MASK) - << AIC3X_HEADSET_DETECT_SHIFT) | - ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK) - << AIC3X_HEADSET_DEBOUNCE_SHIFT) | - ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK) - << AIC3X_BUTTON_DEBOUNCE_SHIFT); - - if (detect & AIC3X_HEADSET_DETECT_MASK) - val |= AIC3X_HEADSET_DETECT_ENABLED; - - aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); -} -EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); - int aic3x_headset_detected(struct snd_soc_codec *codec) { u8 val; - aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); - return (val >> 4) & 1; + aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); + return (val >> 2) & 1; } EXPORT_SYMBOL_GPL(aic3x_headset_detected); -int aic3x_button_pressed(struct snd_soc_codec *codec) -{ - u8 val; - aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); - return (val >> 5) & 1; -} -EXPORT_SYMBOL_GPL(aic3x_button_pressed); - #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -1081,6 +1009,8 @@ struct snd_soc_dai aic3x_dai = { .formats = AIC3X_FORMATS,}, .ops = { .hw_params = aic3x_hw_params, + }, + .dai_ops = { .digital_mute = aic3x_mute, .set_sysclk = aic3x_set_dai_sysclk, .set_fmt = aic3x_set_dai_fmt, @@ -1222,7 +1152,7 @@ static int aic3x_init(struct snd_soc_device *socdev) aic3x_add_controls(codec); aic3x_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "aic3x: failed to register card\n"); goto card_err; @@ -1411,18 +1341,6 @@ struct snd_soc_codec_device soc_codec_dev_aic3x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); -static int __devinit aic3x_modinit(void) -{ - return snd_soc_register_dai(&aic3x_dai); -} -module_init(aic3x_modinit); - -static void __exit aic3x_exit(void) -{ - snd_soc_unregister_dai(&aic3x_dai); -} -module_exit(aic3x_exit); - MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); MODULE_AUTHOR("Vladimir Barinov"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 73e35b6ec929..00a195aa02e4 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -39,9 +39,7 @@ #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 /* Audio codec digital filter control register */ #define AIC3X_CODEC_DFILT_CTRL 12 -/* Headset/button press detection register */ -#define AIC3X_HEADSET_DETECT_CTRL_A 13 -#define AIC3X_HEADSET_DETECT_CTRL_B 14 + /* ADC PGA Gain control registers */ #define LADC_VOL 15 #define RADC_VOL 16 @@ -50,9 +48,7 @@ #define MIC3LR_2_RADC_CTRL 18 /* Line1 Input control registers */ #define LINE1L_2_LADC_CTRL 19 -#define LINE1R_2_LADC_CTRL 21 #define LINE1R_2_RADC_CTRL 22 -#define LINE1L_2_RADC_CTRL 24 /* Line2 Input control registers */ #define LINE2L_2_LADC_CTRL 20 #define LINE2R_2_RADC_CTRL 23 @@ -83,8 +79,6 @@ #define LINE2L_2_HPLOUT_VOL 45 #define LINE2R_2_HPROUT_VOL 62 #define PGAL_2_HPLOUT_VOL 46 -#define PGAL_2_HPROUT_VOL 60 -#define PGAR_2_HPLOUT_VOL 49 #define PGAR_2_HPROUT_VOL 63 #define DACL1_2_HPLOUT_VOL 47 #define DACR1_2_HPROUT_VOL 64 @@ -94,8 +88,6 @@ #define LINE2L_2_HPLCOM_VOL 52 #define LINE2R_2_HPRCOM_VOL 69 #define PGAL_2_HPLCOM_VOL 53 -#define PGAR_2_HPLCOM_VOL 56 -#define PGAL_2_HPRCOM_VOL 67 #define PGAR_2_HPRCOM_VOL 70 #define DACL1_2_HPLCOM_VOL 54 #define DACR1_2_HPRCOM_VOL 71 @@ -111,17 +103,11 @@ #define MONOLOPM_CTRL 79 /* Line Output Plus/Minus control registers */ #define LINE2L_2_LLOPM_VOL 80 -#define LINE2L_2_RLOPM_VOL 87 -#define LINE2R_2_LLOPM_VOL 83 #define LINE2R_2_RLOPM_VOL 90 #define PGAL_2_LLOPM_VOL 81 -#define PGAL_2_RLOPM_VOL 88 -#define PGAR_2_LLOPM_VOL 84 #define PGAR_2_RLOPM_VOL 91 #define DACL1_2_LLOPM_VOL 82 -#define DACL1_2_RLOPM_VOL 89 #define DACR1_2_RLOPM_VOL 92 -#define DACR1_2_LLOPM_VOL 85 #define LLOPM_CTRL 86 #define RLOPM_CTRL 93 /* GPIO/IRQ registers */ @@ -235,49 +221,7 @@ enum { void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); - -/* headset detection / button API */ - -/* The AIC3x supports detection of stereo headsets (GND + left + right signal) - * and cellular headsets (GND + speaker output + microphone input). - * It is recommended to enable MIC bias for this function to work properly. - * For more information, please refer to the datasheet. */ -enum { - AIC3X_HEADSET_DETECT_OFF = 0, - AIC3X_HEADSET_DETECT_STEREO = 1, - AIC3X_HEADSET_DETECT_CELLULAR = 2, - AIC3X_HEADSET_DETECT_BOTH = 3 -}; - -enum { - AIC3X_HEADSET_DEBOUNCE_16MS = 0, - AIC3X_HEADSET_DEBOUNCE_32MS = 1, - AIC3X_HEADSET_DEBOUNCE_64MS = 2, - AIC3X_HEADSET_DEBOUNCE_128MS = 3, - AIC3X_HEADSET_DEBOUNCE_256MS = 4, - AIC3X_HEADSET_DEBOUNCE_512MS = 5 -}; - -enum { - AIC3X_BUTTON_DEBOUNCE_0MS = 0, - AIC3X_BUTTON_DEBOUNCE_8MS = 1, - AIC3X_BUTTON_DEBOUNCE_16MS = 2, - AIC3X_BUTTON_DEBOUNCE_32MS = 3 -}; - -#define AIC3X_HEADSET_DETECT_ENABLED 0x80 -#define AIC3X_HEADSET_DETECT_SHIFT 5 -#define AIC3X_HEADSET_DETECT_MASK 3 -#define AIC3X_HEADSET_DEBOUNCE_SHIFT 2 -#define AIC3X_HEADSET_DEBOUNCE_MASK 7 -#define AIC3X_BUTTON_DEBOUNCE_SHIFT 0 -#define AIC3X_BUTTON_DEBOUNCE_MASK 3 - -/* see the enums above for valid parameters to this function */ -void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, - int headset_debounce, int button_debounce); int aic3x_headset_detected(struct snd_soc_codec *codec); -int aic3x_button_pressed(struct snd_soc_codec *codec); struct aic3x_setup_data { int i2c_bus; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c deleted file mode 100644 index 373daa486cea..000000000000 --- a/sound/soc/codecs/twl4030.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* - * ALSA SoC TWL4030 codec driver - * - * Author: Steve Sakoman, <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/i2c.h> -#include <linux/platform_device.h> -#include <linux/i2c/twl4030.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/initval.h> -#include <sound/tlv.h> - -#include "twl4030.h" - -/* - * twl4030 register cache & default register settings - */ -static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { - 0x00, /* this register not used */ - 0x93, /* REG_CODEC_MODE (0x1) */ - 0xc3, /* REG_OPTION (0x2) */ - 0x00, /* REG_UNKNOWN (0x3) */ - 0x00, /* REG_MICBIAS_CTL (0x4) */ - 0x20, /* REG_ANAMICL (0x5) */ - 0x00, /* REG_ANAMICR (0x6) */ - 0x00, /* REG_AVADC_CTL (0x7) */ - 0x00, /* REG_ADCMICSEL (0x8) */ - 0x00, /* REG_DIGMIXING (0x9) */ - 0x0c, /* REG_ATXL1PGA (0xA) */ - 0x0c, /* REG_ATXR1PGA (0xB) */ - 0x00, /* REG_AVTXL2PGA (0xC) */ - 0x00, /* REG_AVTXR2PGA (0xD) */ - 0x01, /* REG_AUDIO_IF (0xE) */ - 0x00, /* REG_VOICE_IF (0xF) */ - 0x00, /* REG_ARXR1PGA (0x10) */ - 0x00, /* REG_ARXL1PGA (0x11) */ - 0x6c, /* REG_ARXR2PGA (0x12) */ - 0x6c, /* REG_ARXL2PGA (0x13) */ - 0x00, /* REG_VRXPGA (0x14) */ - 0x00, /* REG_VSTPGA (0x15) */ - 0x00, /* REG_VRX2ARXPGA (0x16) */ - 0x0c, /* REG_AVDAC_CTL (0x17) */ - 0x00, /* REG_ARX2VTXPGA (0x18) */ - 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ - 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ - 0x4b, /* REG_ARXL2_APGA_CTL (0x1B) */ - 0x4b, /* REG_ARXR2_APGA_CTL (0x1C) */ - 0x00, /* REG_ATX2ARXPGA (0x1D) */ - 0x00, /* REG_BT_IF (0x1E) */ - 0x00, /* REG_BTPGA (0x1F) */ - 0x00, /* REG_BTSTPGA (0x20) */ - 0x00, /* REG_EAR_CTL (0x21) */ - 0x24, /* REG_HS_SEL (0x22) */ - 0x0a, /* REG_HS_GAIN_SET (0x23) */ - 0x00, /* REG_HS_POPN_SET (0x24) */ - 0x00, /* REG_PREDL_CTL (0x25) */ - 0x00, /* REG_PREDR_CTL (0x26) */ - 0x00, /* REG_PRECKL_CTL (0x27) */ - 0x00, /* REG_PRECKR_CTL (0x28) */ - 0x00, /* REG_HFL_CTL (0x29) */ - 0x00, /* REG_HFR_CTL (0x2A) */ - 0x00, /* REG_ALC_CTL (0x2B) */ - 0x00, /* REG_ALC_SET1 (0x2C) */ - 0x00, /* REG_ALC_SET2 (0x2D) */ - 0x00, /* REG_BOOST_CTL (0x2E) */ - 0x00, /* REG_SOFTVOL_CTL (0x2F) */ - 0x00, /* REG_DTMF_FREQSEL (0x30) */ - 0x00, /* REG_DTMF_TONEXT1H (0x31) */ - 0x00, /* REG_DTMF_TONEXT1L (0x32) */ - 0x00, /* REG_DTMF_TONEXT2H (0x33) */ - 0x00, /* REG_DTMF_TONEXT2L (0x34) */ - 0x00, /* REG_DTMF_TONOFF (0x35) */ - 0x00, /* REG_DTMF_WANONOFF (0x36) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ - 0x16, /* REG_APLL_CTL (0x3A) */ - 0x00, /* REG_DTMF_CTL (0x3B) */ - 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ - 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ - 0x00, /* REG_MISC_SET_1 (0x3E) */ - 0x00, /* REG_PCMBTMUX (0x3F) */ - 0x00, /* not used (0x40) */ - 0x00, /* not used (0x41) */ - 0x00, /* not used (0x42) */ - 0x00, /* REG_RX_PATH_SEL (0x43) */ - 0x00, /* REG_VDL_APGA_CTL (0x44) */ - 0x00, /* REG_VIBRA_CTL (0x45) */ - 0x00, /* REG_VIBRA_SET (0x46) */ - 0x00, /* REG_VIBRA_PWM_SET (0x47) */ - 0x00, /* REG_ANAMIC_GAIN (0x48) */ - 0x00, /* REG_MISC_SET_2 (0x49) */ -}; - -/* - * read twl4030 register cache - */ -static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *cache = codec->reg_cache; - - return cache[reg]; -} - -/* - * write twl4030 register cache - */ -static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, u8 value) -{ - u8 *cache = codec->reg_cache; - - if (reg >= TWL4030_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the twl4030 register space - */ -static int twl4030_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - twl4030_write_reg_cache(codec, reg, value); - return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); -} - -static void twl4030_clear_codecpdz(struct snd_soc_codec *codec) -{ - u8 mode; - - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); - twl4030_write(codec, TWL4030_REG_CODEC_MODE, - mode & ~TWL4030_CODECPDZ); - - /* REVISIT: this delay is present in TI sample drivers */ - /* but there seems to be no TRM requirement for it */ - udelay(10); -} - -static void twl4030_set_codecpdz(struct snd_soc_codec *codec) -{ - u8 mode; - - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); - twl4030_write(codec, TWL4030_REG_CODEC_MODE, - mode | TWL4030_CODECPDZ); - - /* REVISIT: this delay is present in TI sample drivers */ - /* but there seems to be no TRM requirement for it */ - udelay(10); -} - -static void twl4030_init_chip(struct snd_soc_codec *codec) -{ - int i; - - /* clear CODECPDZ prior to setting register defaults */ - twl4030_clear_codecpdz(codec); - - /* set all audio section registers to reasonable defaults */ - for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) - twl4030_write(codec, i, twl4030_reg[i]); - -} - -/* Earpiece */ -static const char *twl4030_earpiece_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR1"}; - -static const struct soc_enum twl4030_earpiece_enum = - SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, - ARRAY_SIZE(twl4030_earpiece_texts), - twl4030_earpiece_texts); - -static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = -SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); - -/* PreDrive Left */ -static const char *twl4030_predrivel_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR2"}; - -static const struct soc_enum twl4030_predrivel_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, - ARRAY_SIZE(twl4030_predrivel_texts), - twl4030_predrivel_texts); - -static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = -SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); - -/* PreDrive Right */ -static const char *twl4030_predriver_texts[] = - {"Off", "DACR1", "DACR2", "Invalid", - "DACL2"}; - -static const struct soc_enum twl4030_predriver_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, - ARRAY_SIZE(twl4030_predriver_texts), - twl4030_predriver_texts); - -static const struct snd_kcontrol_new twl4030_dapm_predriver_control = -SOC_DAPM_ENUM("Route", twl4030_predriver_enum); - -/* Headset Left */ -static const char *twl4030_hsol_texts[] = - {"Off", "DACL1", "DACL2"}; - -static const struct soc_enum twl4030_hsol_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1, - ARRAY_SIZE(twl4030_hsol_texts), - twl4030_hsol_texts); - -static const struct snd_kcontrol_new twl4030_dapm_hsol_control = -SOC_DAPM_ENUM("Route", twl4030_hsol_enum); - -/* Headset Right */ -static const char *twl4030_hsor_texts[] = - {"Off", "DACR1", "DACR2"}; - -static const struct soc_enum twl4030_hsor_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4, - ARRAY_SIZE(twl4030_hsor_texts), - twl4030_hsor_texts); - -static const struct snd_kcontrol_new twl4030_dapm_hsor_control = -SOC_DAPM_ENUM("Route", twl4030_hsor_enum); - -/* Carkit Left */ -static const char *twl4030_carkitl_texts[] = - {"Off", "DACL1", "DACL2"}; - -static const struct soc_enum twl4030_carkitl_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1, - ARRAY_SIZE(twl4030_carkitl_texts), - twl4030_carkitl_texts); - -static const struct snd_kcontrol_new twl4030_dapm_carkitl_control = -SOC_DAPM_ENUM("Route", twl4030_carkitl_enum); - -/* Carkit Right */ -static const char *twl4030_carkitr_texts[] = - {"Off", "DACR1", "DACR2"}; - -static const struct soc_enum twl4030_carkitr_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1, - ARRAY_SIZE(twl4030_carkitr_texts), - twl4030_carkitr_texts); - -static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = -SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); - -/* Handsfree Left */ -static const char *twl4030_handsfreel_texts[] = - {"Voice", "DACL1", "DACL2", "DACR2"}; - -static const struct soc_enum twl4030_handsfreel_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, - ARRAY_SIZE(twl4030_handsfreel_texts), - twl4030_handsfreel_texts); - -static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = -SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); - -/* Handsfree Right */ -static const char *twl4030_handsfreer_texts[] = - {"Voice", "DACR1", "DACR2", "DACL2"}; - -static const struct soc_enum twl4030_handsfreer_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, - ARRAY_SIZE(twl4030_handsfreer_texts), - twl4030_handsfreer_texts); - -static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = -SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); - -static int outmixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int ret = 0; - int val; - - switch (e->reg) { - case TWL4030_REG_PREDL_CTL: - case TWL4030_REG_PREDR_CTL: - case TWL4030_REG_EAR_CTL: - val = w->value >> e->shift_l; - if (val == 3) { - printk(KERN_WARNING - "Invalid MUX setting for register 0x%02x (%d)\n", - e->reg, val); - ret = -1; - } - break; - } - - return ret; -} - -/* - * Some of the gain controls in TWL (mostly those which are associated with - * the outputs) are implemented in an interesting way: - * 0x0 : Power down (mute) - * 0x1 : 6dB - * 0x2 : 0 dB - * 0x3 : -6 dB - * Inverting not going to help with these. - * Custom volsw and volsw_2r get/put functions to handle these gain bits. - */ -#define SOC_DOUBLE_TLV_TWL4030(xname, xreg, shift_left, shift_right, xmax,\ - xinvert, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, \ - .get = snd_soc_get_volsw_twl4030, \ - .put = snd_soc_put_volsw_twl4030, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ - .max = xmax, .invert = xinvert} } -#define SOC_DOUBLE_R_TLV_TWL4030(xname, reg_left, reg_right, xshift, xmax,\ - xinvert, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw_2r, \ - .get = snd_soc_get_volsw_r2_twl4030,\ - .put = snd_soc_put_volsw_r2_twl4030, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ - .rshift = xshift, .max = xmax, .invert = xinvert} } -#define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \ - SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \ - xinvert, tlv_array) - -static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int mask = (1 << fls(max)) - 1; - - ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; - if (ucontrol->value.integer.value[0]) - ucontrol->value.integer.value[0] = - max + 1 - ucontrol->value.integer.value[0]; - - if (shift != rshift) { - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg) >> rshift) & mask; - if (ucontrol->value.integer.value[1]) - ucontrol->value.integer.value[1] = - max + 1 - ucontrol->value.integer.value[1]; - } - - return 0; -} - -static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int mask = (1 << fls(max)) - 1; - unsigned short val, val2, val_mask; - - val = (ucontrol->value.integer.value[0] & mask); - - val_mask = mask << shift; - if (val) - val = max + 1 - val; - val = val << shift; - if (shift != rshift) { - val2 = (ucontrol->value.integer.value[1] & mask); - val_mask |= mask << rshift; - if (val2) - val2 = max + 1 - val2; - val |= val2 << rshift; - } - return snd_soc_update_bits(codec, reg, val_mask, val); -} - -static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - int max = mc->max; - int mask = (1<<fls(max))-1; - - ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg2) >> shift) & mask; - - if (ucontrol->value.integer.value[0]) - ucontrol->value.integer.value[0] = - max + 1 - ucontrol->value.integer.value[0]; - if (ucontrol->value.integer.value[1]) - ucontrol->value.integer.value[1] = - max + 1 - ucontrol->value.integer.value[1]; - - return 0; -} - -static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - int max = mc->max; - int mask = (1 << fls(max)) - 1; - int err; - unsigned short val, val2, val_mask; - - val_mask = mask << shift; - val = (ucontrol->value.integer.value[0] & mask); - val2 = (ucontrol->value.integer.value[1] & mask); - - if (val) - val = max + 1 - val; - if (val2) - val2 = max + 1 - val2; - - val = val << shift; - val2 = val2 << shift; - - err = snd_soc_update_bits(codec, reg, val_mask, val); - if (err < 0) - return err; - - err = snd_soc_update_bits(codec, reg2, val_mask, val2); - return err; -} - -static int twl4030_get_left_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - int result = 0; - - /* one bit must be set a time */ - reg &= TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN - | TWL4030_MAINMIC_EN; - if (reg != 0) { - result++; - while ((reg & 1) == 0) { - result++; - reg >>= 1; - } - } - - ucontrol->value.integer.value[0] = result; - return 0; -} - -static int twl4030_put_left_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - int value = ucontrol->value.integer.value[0]; - u8 anamicl, micbias, avadc_ctl; - - anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - anamicl &= ~(TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN - | TWL4030_MAINMIC_EN); - micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); - micbias &= ~(TWL4030_HSMICBIAS_EN | TWL4030_MICBIAS1_EN); - avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); - - switch (value) { - case 1: - anamicl |= TWL4030_MAINMIC_EN; - micbias |= TWL4030_MICBIAS1_EN; - break; - case 2: - anamicl |= TWL4030_HSMIC_EN; - micbias |= TWL4030_HSMICBIAS_EN; - break; - case 3: - anamicl |= TWL4030_AUXL_EN; - break; - case 4: - anamicl |= TWL4030_CKMIC_EN; - break; - default: - break; - } - - /* If some input is selected, enable amp and ADC */ - if (value != 0) { - anamicl |= TWL4030_MICAMPL_EN; - avadc_ctl |= TWL4030_ADCL_EN; - } else { - anamicl &= ~TWL4030_MICAMPL_EN; - avadc_ctl &= ~TWL4030_ADCL_EN; - } - - twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl); - twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); - twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); - - return 1; -} - -static int twl4030_get_right_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); - int value = 0; - - reg &= TWL4030_SUBMIC_EN|TWL4030_AUXR_EN; - switch (reg) { - case TWL4030_SUBMIC_EN: - value = 1; - break; - case TWL4030_AUXR_EN: - value = 2; - break; - default: - break; - } - - ucontrol->value.integer.value[0] = value; - return 0; -} - -static int twl4030_put_right_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - int value = ucontrol->value.integer.value[0]; - u8 anamicr, micbias, avadc_ctl; - - anamicr = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); - anamicr &= ~(TWL4030_SUBMIC_EN|TWL4030_AUXR_EN); - micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); - micbias &= ~TWL4030_MICBIAS2_EN; - avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); - - switch (value) { - case 1: - anamicr |= TWL4030_SUBMIC_EN; - micbias |= TWL4030_MICBIAS2_EN; - break; - case 2: - anamicr |= TWL4030_AUXR_EN; - break; - default: - break; - } - - if (value != 0) { - anamicr |= TWL4030_MICAMPR_EN; - avadc_ctl |= TWL4030_ADCR_EN; - } else { - anamicr &= ~TWL4030_MICAMPR_EN; - avadc_ctl &= ~TWL4030_ADCR_EN; - } - - twl4030_write(codec, TWL4030_REG_ANAMICR, anamicr); - twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); - twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); - - return 1; -} - -static const char *twl4030_left_in_sel[] = { - "None", - "Main Mic", - "Headset Mic", - "Line In", - "Carkit Mic", -}; - -static const char *twl4030_right_in_sel[] = { - "None", - "Sub Mic", - "Line In", -}; - -static const struct soc_enum twl4030_left_input_mux = - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_left_in_sel), - twl4030_left_in_sel); - -static const struct soc_enum twl4030_right_input_mux = - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_right_in_sel), - twl4030_right_in_sel); - -/* - * FGAIN volume control: - * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) - */ -static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1); - -/* - * CGAIN volume control: - * 0 dB to 12 dB in 6 dB steps - * value 2 and 3 means 12 dB - */ -static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); - -/* - * Analog playback gain - * -24 dB to 12 dB in 2 dB steps - */ -static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0); - -/* - * Gain controls tied to outputs - * -6 dB to 6 dB in 6 dB steps (mute instead of -12) - */ -static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1); - -/* - * Capture gain after the ADCs - * from 0 dB to 31 dB in 1 dB steps - */ -static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); - -/* - * Gain control for input amplifiers - * 0 dB to 30 dB in 6 dB steps - */ -static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); - -static const struct snd_kcontrol_new twl4030_snd_controls[] = { - /* Common playback gain controls */ - SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", - TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, - 0, 0x3f, 0, digital_fine_tlv), - SOC_DOUBLE_R_TLV("DAC2 Digital Fine Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 0x3f, 0, digital_fine_tlv), - - SOC_DOUBLE_R_TLV("DAC1 Digital Coarse Playback Volume", - TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, - 6, 0x2, 0, digital_coarse_tlv), - SOC_DOUBLE_R_TLV("DAC2 Digital Coarse Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 6, 0x2, 0, digital_coarse_tlv), - - SOC_DOUBLE_R_TLV("DAC1 Analog Playback Volume", - TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, - 3, 0x12, 1, analog_tlv), - SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume", - TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, - 3, 0x12, 1, analog_tlv), - SOC_DOUBLE_R("DAC1 Analog Playback Switch", - TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, - 1, 1, 0), - SOC_DOUBLE_R("DAC2 Analog Playback Switch", - TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, - 1, 1, 0), - - /* Separate output gain controls */ - SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", - TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, - 4, 3, 0, output_tvl), - - SOC_DOUBLE_TLV_TWL4030("Headset Playback Volume", - TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, output_tvl), - - SOC_DOUBLE_R_TLV_TWL4030("Carkit Playback Volume", - TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL, - 4, 3, 0, output_tvl), - - SOC_SINGLE_TLV_TWL4030("Earpiece Playback Volume", - TWL4030_REG_EAR_CTL, 4, 3, 0, output_tvl), - - /* Common capture gain controls */ - SOC_DOUBLE_R_TLV("Capture Volume", - TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, - 0, 0x1f, 0, digital_capture_tlv), - - SOC_DOUBLE_TLV("Input Boost Volume", TWL4030_REG_ANAMIC_GAIN, - 0, 3, 5, 0, input_gain_tlv), - - /* Input source controls */ - SOC_ENUM_EXT("Left Input Source", twl4030_left_input_mux, - twl4030_get_left_input, twl4030_put_left_input), - SOC_ENUM_EXT("Right Input Source", twl4030_right_input_mux, - twl4030_get_right_input, twl4030_put_right_input), -}; - -/* add non dapm controls */ -static int twl4030_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&twl4030_snd_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("INL"), - SND_SOC_DAPM_INPUT("INR"), - - SND_SOC_DAPM_OUTPUT("OUTL"), - SND_SOC_DAPM_OUTPUT("OUTR"), - SND_SOC_DAPM_OUTPUT("EARPIECE"), - SND_SOC_DAPM_OUTPUT("PREDRIVEL"), - SND_SOC_DAPM_OUTPUT("PREDRIVER"), - SND_SOC_DAPM_OUTPUT("HSOL"), - SND_SOC_DAPM_OUTPUT("HSOR"), - SND_SOC_DAPM_OUTPUT("HFL"), - SND_SOC_DAPM_OUTPUT("HFR"), - - /* DACs */ - SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", - TWL4030_REG_AVDAC_CTL, 0, 0), - SND_SOC_DAPM_DAC("DACL1", "Left Front Playback", - TWL4030_REG_AVDAC_CTL, 1, 0), - SND_SOC_DAPM_DAC("DACR2", "Right Rear Playback", - TWL4030_REG_AVDAC_CTL, 2, 0), - SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", - TWL4030_REG_AVDAC_CTL, 3, 0), - - /* Analog PGAs */ - SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, - 0, 0, NULL, 0), - - /* Output MUX controls */ - /* Earpiece */ - SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_earpiece_control, outmixer_event, - SND_SOC_DAPM_PRE_REG), - /* PreDrivL/R */ - SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predrivel_control, outmixer_event, - SND_SOC_DAPM_PRE_REG), - SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predriver_control, outmixer_event, - SND_SOC_DAPM_PRE_REG), - /* HeadsetL/R */ - SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsol_control), - SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsor_control), - /* CarkitL/R */ - SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitl_control), - SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitr_control), - /* HandsfreeL/R */ - SND_SOC_DAPM_MUX("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, - &twl4030_dapm_handsfreel_control), - SND_SOC_DAPM_MUX("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, - &twl4030_dapm_handsfreer_control), - - SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), -}; - -static const struct snd_soc_dapm_route intercon[] = { - {"ARXL1_APGA", NULL, "DACL1"}, - {"ARXR1_APGA", NULL, "DACR1"}, - {"ARXL2_APGA", NULL, "DACL2"}, - {"ARXR2_APGA", NULL, "DACR2"}, - - /* Internal playback routings */ - /* Earpiece */ - {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, - {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, - {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, - /* PreDrivL */ - {"PredriveL Mux", "DACL1", "ARXL1_APGA"}, - {"PredriveL Mux", "DACL2", "ARXL2_APGA"}, - {"PredriveL Mux", "DACR2", "ARXR2_APGA"}, - /* PreDrivR */ - {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, - {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, - {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, - /* HeadsetL */ - {"HeadsetL Mux", "DACL1", "ARXL1_APGA"}, - {"HeadsetL Mux", "DACL2", "ARXL2_APGA"}, - /* HeadsetR */ - {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, - {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, - /* CarkitL */ - {"CarkitL Mux", "DACL1", "ARXL1_APGA"}, - {"CarkitL Mux", "DACL2", "ARXL2_APGA"}, - /* CarkitR */ - {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, - {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, - /* HandsfreeL */ - {"HandsfreeL Mux", "DACL1", "ARXL1_APGA"}, - {"HandsfreeL Mux", "DACL2", "ARXL2_APGA"}, - {"HandsfreeL Mux", "DACR2", "ARXR2_APGA"}, - /* HandsfreeR */ - {"HandsfreeR Mux", "DACR1", "ARXR1_APGA"}, - {"HandsfreeR Mux", "DACR2", "ARXR2_APGA"}, - {"HandsfreeR Mux", "DACL2", "ARXL2_APGA"}, - - /* outputs */ - {"OUTL", NULL, "ARXL2_APGA"}, - {"OUTR", NULL, "ARXR2_APGA"}, - {"EARPIECE", NULL, "Earpiece Mux"}, - {"PREDRIVEL", NULL, "PredriveL Mux"}, - {"PREDRIVER", NULL, "PredriveR Mux"}, - {"HSOL", NULL, "HeadsetL Mux"}, - {"HSOR", NULL, "HeadsetR Mux"}, - {"CARKITL", NULL, "CarkitL Mux"}, - {"CARKITR", NULL, "CarkitR Mux"}, - {"HFL", NULL, "HandsfreeL Mux"}, - {"HFR", NULL, "HandsfreeR Mux"}, - - /* inputs */ - {"ADCL", NULL, "INL"}, - {"ADCR", NULL, "INR"}, -}; - -static int twl4030_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets, - ARRAY_SIZE(twl4030_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - - snd_soc_dapm_new_widgets(codec); - return 0; -} - -static void twl4030_power_up(struct snd_soc_codec *codec) -{ - u8 anamicl, regmisc1, byte, popn; - int i = 0; - - /* set CODECPDZ to turn on codec */ - twl4030_set_codecpdz(codec); - - /* initiate offset cancellation */ - anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - twl4030_write(codec, TWL4030_REG_ANAMICL, - anamicl | TWL4030_CNCL_OFFSET_START); - - /* wait for offset cancellation to complete */ - do { - /* this takes a little while, so don't slam i2c */ - udelay(2000); - twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, - TWL4030_REG_ANAMICL); - } while ((i++ < 100) && - ((byte & TWL4030_CNCL_OFFSET_START) == - TWL4030_CNCL_OFFSET_START)); - - /* anti-pop when changing analog gain */ - regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); - twl4030_write(codec, TWL4030_REG_MISC_SET_1, - regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); - - /* toggle CODECPDZ as per TRM */ - twl4030_clear_codecpdz(codec); - twl4030_set_codecpdz(codec); - - /* program anti-pop with bias ramp delay */ - popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); - popn &= TWL4030_RAMP_DELAY; - popn |= TWL4030_RAMP_DELAY_645MS; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - popn |= TWL4030_VMID_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - - /* enable anti-pop ramp */ - popn |= TWL4030_RAMP_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); -} - -static void twl4030_power_down(struct snd_soc_codec *codec) -{ - u8 popn; - - /* disable anti-pop ramp */ - popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); - popn &= ~TWL4030_RAMP_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - - /* disable bias out */ - popn &= ~TWL4030_VMID_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - - /* power down */ - twl4030_clear_codecpdz(codec); -} - -static int twl4030_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - switch (level) { - case SND_SOC_BIAS_ON: - twl4030_power_up(codec); - break; - case SND_SOC_BIAS_PREPARE: - /* TODO: develop a twl4030_prepare function */ - break; - case SND_SOC_BIAS_STANDBY: - /* TODO: develop a twl4030_standby function */ - twl4030_power_down(codec); - break; - case SND_SOC_BIAS_OFF: - twl4030_power_down(codec); - break; - } - codec->bias_level = level; - - return 0; -} - -static int twl4030_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u8 mode, old_mode, format, old_format; - - - /* bit rate */ - old_mode = twl4030_read_reg_cache(codec, - TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; - mode = old_mode & ~TWL4030_APLL_RATE; - - switch (params_rate(params)) { - case 8000: - mode |= TWL4030_APLL_RATE_8000; - break; - case 11025: - mode |= TWL4030_APLL_RATE_11025; - break; - case 12000: - mode |= TWL4030_APLL_RATE_12000; - break; - case 16000: - mode |= TWL4030_APLL_RATE_16000; - break; - case 22050: - mode |= TWL4030_APLL_RATE_22050; - break; - case 24000: - mode |= TWL4030_APLL_RATE_24000; - break; - case 32000: - mode |= TWL4030_APLL_RATE_32000; - break; - case 44100: - mode |= TWL4030_APLL_RATE_44100; - break; - case 48000: - mode |= TWL4030_APLL_RATE_48000; - break; - default: - printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", - params_rate(params)); - return -EINVAL; - } - - if (mode != old_mode) { - /* change rate and set CODECPDZ */ - twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); - twl4030_set_codecpdz(codec); - } - - /* sample size */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); - format = old_format; - format &= ~TWL4030_DATA_WIDTH; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - format |= TWL4030_DATA_WIDTH_16S_16W; - break; - case SNDRV_PCM_FORMAT_S24_LE: - format |= TWL4030_DATA_WIDTH_32S_24W; - break; - default: - printk(KERN_ERR "TWL4030 hw params: unknown format %d\n", - params_format(params)); - return -EINVAL; - } - - if (format != old_format) { - - /* clear CODECPDZ before changing format (codec requirement) */ - twl4030_clear_codecpdz(codec); - - /* change format */ - twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); - - /* set CODECPDZ afterwards */ - twl4030_set_codecpdz(codec); - } - return 0; -} - -static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u8 infreq; - - switch (freq) { - case 19200000: - infreq = TWL4030_APLL_INFREQ_19200KHZ; - break; - case 26000000: - infreq = TWL4030_APLL_INFREQ_26000KHZ; - break; - case 38400000: - infreq = TWL4030_APLL_INFREQ_38400KHZ; - break; - default: - printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n", - freq); - return -EINVAL; - } - - infreq |= TWL4030_APLL_EN; - twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); - - return 0; -} - -static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u8 old_format, format; - - /* get format */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); - format = old_format; - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - format &= ~(TWL4030_AIF_SLAVE_EN); - format &= ~(TWL4030_CLK256FS_EN); - break; - case SND_SOC_DAIFMT_CBS_CFS: - format |= TWL4030_AIF_SLAVE_EN; - format |= TWL4030_CLK256FS_EN; - break; - default: - return -EINVAL; - } - - /* interface format */ - format &= ~TWL4030_AIF_FORMAT; - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - format |= TWL4030_AIF_FORMAT_CODEC; - break; - default: - return -EINVAL; - } - - if (format != old_format) { - - /* clear CODECPDZ before changing format (codec requirement) */ - twl4030_clear_codecpdz(codec); - - /* change format */ - twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); - - /* set CODECPDZ afterwards */ - twl4030_set_codecpdz(codec); - } - - return 0; -} - -#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) -#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) - -struct snd_soc_dai twl4030_dai = { - .name = "twl4030", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = TWL4030_RATES, - .formats = TWL4030_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - .rates = TWL4030_RATES, - .formats = TWL4030_FORMATS,}, - .ops = { - .hw_params = twl4030_hw_params, - .set_sysclk = twl4030_set_dai_sysclk, - .set_fmt = twl4030_set_dai_fmt, - } -}; -EXPORT_SYMBOL_GPL(twl4030_dai); - -static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int twl4030_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - twl4030_set_bias_level(codec, codec->suspend_bias_level); - return 0; -} - -/* - * initialize the driver - * register the mixer and dsp interfaces with the kernel - */ - -static int twl4030_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; - - printk(KERN_INFO "TWL4030 Audio Codec init \n"); - - codec->name = "twl4030"; - codec->owner = THIS_MODULE; - codec->read = twl4030_read_reg_cache; - codec->write = twl4030_write; - codec->set_bias_level = twl4030_set_bias_level; - codec->dai = &twl4030_dai; - codec->num_dai = 1; - codec->reg_cache_size = sizeof(twl4030_reg); - codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "twl4030: failed to create pcms\n"); - goto pcm_err; - } - - twl4030_init_chip(codec); - - /* power on device */ - twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - twl4030_add_controls(codec); - twl4030_add_widgets(codec); - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "twl4030: failed to register card\n"); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -static struct snd_soc_device *twl4030_socdev; - -static int twl4030_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - twl4030_socdev = socdev; - twl4030_init(socdev); - - return 0; -} - -static int twl4030_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - printk(KERN_INFO "TWL4030 Audio Codec remove\n"); - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_twl4030 = { - .probe = twl4030_probe, - .remove = twl4030_remove, - .suspend = twl4030_suspend, - .resume = twl4030_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); - -static int __devinit twl4030_init(void) -{ - return snd_soc_register_dai(&twl4030_dai); -} -module_init(twl4030_init); - -static void __exit twl4030_exit(void) -{ - snd_soc_unregister_dai(&twl4030_dai); -} -module_exit(twl4030_exit); - -MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); -MODULE_AUTHOR("Steve Sakoman"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h deleted file mode 100644 index a2065d417c2e..000000000000 --- a/sound/soc/codecs/twl4030.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * ALSA SoC TWL4030 codec driver - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __TWL4030_AUDIO_H__ -#define __TWL4030_AUDIO_H__ - -#define TWL4030_REG_CODEC_MODE 0x1 -#define TWL4030_REG_OPTION 0x2 -#define TWL4030_REG_UNKNOWN 0x3 -#define TWL4030_REG_MICBIAS_CTL 0x4 -#define TWL4030_REG_ANAMICL 0x5 -#define TWL4030_REG_ANAMICR 0x6 -#define TWL4030_REG_AVADC_CTL 0x7 -#define TWL4030_REG_ADCMICSEL 0x8 -#define TWL4030_REG_DIGMIXING 0x9 -#define TWL4030_REG_ATXL1PGA 0xA -#define TWL4030_REG_ATXR1PGA 0xB -#define TWL4030_REG_AVTXL2PGA 0xC -#define TWL4030_REG_AVTXR2PGA 0xD -#define TWL4030_REG_AUDIO_IF 0xE -#define TWL4030_REG_VOICE_IF 0xF -#define TWL4030_REG_ARXR1PGA 0x10 -#define TWL4030_REG_ARXL1PGA 0x11 -#define TWL4030_REG_ARXR2PGA 0x12 -#define TWL4030_REG_ARXL2PGA 0x13 -#define TWL4030_REG_VRXPGA 0x14 -#define TWL4030_REG_VSTPGA 0x15 -#define TWL4030_REG_VRX2ARXPGA 0x16 -#define TWL4030_REG_AVDAC_CTL 0x17 -#define TWL4030_REG_ARX2VTXPGA 0x18 -#define TWL4030_REG_ARXL1_APGA_CTL 0x19 -#define TWL4030_REG_ARXR1_APGA_CTL 0x1A -#define TWL4030_REG_ARXL2_APGA_CTL 0x1B -#define TWL4030_REG_ARXR2_APGA_CTL 0x1C -#define TWL4030_REG_ATX2ARXPGA 0x1D -#define TWL4030_REG_BT_IF 0x1E -#define TWL4030_REG_BTPGA 0x1F -#define TWL4030_REG_BTSTPGA 0x20 -#define TWL4030_REG_EAR_CTL 0x21 -#define TWL4030_REG_HS_SEL 0x22 -#define TWL4030_REG_HS_GAIN_SET 0x23 -#define TWL4030_REG_HS_POPN_SET 0x24 -#define TWL4030_REG_PREDL_CTL 0x25 -#define TWL4030_REG_PREDR_CTL 0x26 -#define TWL4030_REG_PRECKL_CTL 0x27 -#define TWL4030_REG_PRECKR_CTL 0x28 -#define TWL4030_REG_HFL_CTL 0x29 -#define TWL4030_REG_HFR_CTL 0x2A -#define TWL4030_REG_ALC_CTL 0x2B -#define TWL4030_REG_ALC_SET1 0x2C -#define TWL4030_REG_ALC_SET2 0x2D -#define TWL4030_REG_BOOST_CTL 0x2E -#define TWL4030_REG_SOFTVOL_CTL 0x2F -#define TWL4030_REG_DTMF_FREQSEL 0x30 -#define TWL4030_REG_DTMF_TONEXT1H 0x31 -#define TWL4030_REG_DTMF_TONEXT1L 0x32 -#define TWL4030_REG_DTMF_TONEXT2H 0x33 -#define TWL4030_REG_DTMF_TONEXT2L 0x34 -#define TWL4030_REG_DTMF_TONOFF 0x35 -#define TWL4030_REG_DTMF_WANONOFF 0x36 -#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37 -#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38 -#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39 -#define TWL4030_REG_APLL_CTL 0x3A -#define TWL4030_REG_DTMF_CTL 0x3B -#define TWL4030_REG_DTMF_PGA_CTL2 0x3C -#define TWL4030_REG_DTMF_PGA_CTL1 0x3D -#define TWL4030_REG_MISC_SET_1 0x3E -#define TWL4030_REG_PCMBTMUX 0x3F -#define TWL4030_REG_RX_PATH_SEL 0x43 -#define TWL4030_REG_VDL_APGA_CTL 0x44 -#define TWL4030_REG_VIBRA_CTL 0x45 -#define TWL4030_REG_VIBRA_SET 0x46 -#define TWL4030_REG_VIBRA_PWM_SET 0x47 -#define TWL4030_REG_ANAMIC_GAIN 0x48 -#define TWL4030_REG_MISC_SET_2 0x49 - -#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) - -/* Bitfield Definitions */ - -/* TWL4030_CODEC_MODE (0x01) Fields */ - -#define TWL4030_APLL_RATE 0xF0 -#define TWL4030_APLL_RATE_8000 0x00 -#define TWL4030_APLL_RATE_11025 0x10 -#define TWL4030_APLL_RATE_12000 0x20 -#define TWL4030_APLL_RATE_16000 0x40 -#define TWL4030_APLL_RATE_22050 0x50 -#define TWL4030_APLL_RATE_24000 0x60 -#define TWL4030_APLL_RATE_32000 0x80 -#define TWL4030_APLL_RATE_44100 0x90 -#define TWL4030_APLL_RATE_48000 0xA0 -#define TWL4030_SEL_16K 0x04 -#define TWL4030_CODECPDZ 0x02 -#define TWL4030_OPT_MODE 0x01 - -/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ - -#define TWL4030_MICBIAS2_CTL 0x40 -#define TWL4030_MICBIAS1_CTL 0x20 -#define TWL4030_HSMICBIAS_EN 0x04 -#define TWL4030_MICBIAS2_EN 0x02 -#define TWL4030_MICBIAS1_EN 0x01 - -/* ANAMICL (0x05) Fields */ - -#define TWL4030_CNCL_OFFSET_START 0x80 -#define TWL4030_OFFSET_CNCL_SEL 0x60 -#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 -#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20 -#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40 -#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60 -#define TWL4030_MICAMPL_EN 0x10 -#define TWL4030_CKMIC_EN 0x08 -#define TWL4030_AUXL_EN 0x04 -#define TWL4030_HSMIC_EN 0x02 -#define TWL4030_MAINMIC_EN 0x01 - -/* ANAMICR (0x06) Fields */ - -#define TWL4030_MICAMPR_EN 0x10 -#define TWL4030_AUXR_EN 0x04 -#define TWL4030_SUBMIC_EN 0x01 - -/* AVADC_CTL (0x07) Fields */ - -#define TWL4030_ADCL_EN 0x08 -#define TWL4030_AVADC_CLK_PRIORITY 0x04 -#define TWL4030_ADCR_EN 0x02 - -/* AUDIO_IF (0x0E) Fields */ - -#define TWL4030_AIF_SLAVE_EN 0x80 -#define TWL4030_DATA_WIDTH 0x60 -#define TWL4030_DATA_WIDTH_16S_16W 0x00 -#define TWL4030_DATA_WIDTH_32S_16W 0x40 -#define TWL4030_DATA_WIDTH_32S_24W 0x60 -#define TWL4030_AIF_FORMAT 0x18 -#define TWL4030_AIF_FORMAT_CODEC 0x00 -#define TWL4030_AIF_FORMAT_LEFT 0x08 -#define TWL4030_AIF_FORMAT_RIGHT 0x10 -#define TWL4030_AIF_FORMAT_TDM 0x18 -#define TWL4030_AIF_TRI_EN 0x04 -#define TWL4030_CLK256FS_EN 0x02 -#define TWL4030_AIF_EN 0x01 - -/* HS_GAIN_SET (0x23) Fields */ - -#define TWL4030_HSR_GAIN 0x0C -#define TWL4030_HSR_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSR_GAIN_PLUS_6DB 0x04 -#define TWL4030_HSR_GAIN_0DB 0x08 -#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C -#define TWL4030_HSL_GAIN 0x03 -#define TWL4030_HSL_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSL_GAIN_PLUS_6DB 0x01 -#define TWL4030_HSL_GAIN_0DB 0x02 -#define TWL4030_HSL_GAIN_MINUS_6DB 0x03 - -/* HS_POPN_SET (0x24) Fields */ - -#define TWL4030_VMID_EN 0x40 -#define TWL4030_EXTMUTE 0x20 -#define TWL4030_RAMP_DELAY 0x1C -#define TWL4030_RAMP_DELAY_20MS 0x00 -#define TWL4030_RAMP_DELAY_40MS 0x04 -#define TWL4030_RAMP_DELAY_81MS 0x08 -#define TWL4030_RAMP_DELAY_161MS 0x0C -#define TWL4030_RAMP_DELAY_323MS 0x10 -#define TWL4030_RAMP_DELAY_645MS 0x14 -#define TWL4030_RAMP_DELAY_1291MS 0x18 -#define TWL4030_RAMP_DELAY_2581MS 0x1C -#define TWL4030_RAMP_EN 0x02 - -/* APLL_CTL (0x3A) Fields */ - -#define TWL4030_APLL_EN 0x10 -#define TWL4030_APLL_INFREQ 0x0F -#define TWL4030_APLL_INFREQ_19200KHZ 0x05 -#define TWL4030_APLL_INFREQ_26000KHZ 0x06 -#define TWL4030_APLL_INFREQ_38400KHZ 0x0F - -/* REG_MISC_SET_1 (0x3E) Fields */ - -#define TWL4030_CLK64_EN 0x80 -#define TWL4030_SCRAMBLE_EN 0x40 -#define TWL4030_FMLOOP_EN 0x20 -#define TWL4030_SMOOTH_ANAVOL_EN 0x02 -#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 - -extern struct snd_soc_dai twl4030_dai; -extern struct snd_soc_codec_device soc_codec_dev_twl4030; - -#endif /* End of __TWL4030_AUDIO_H__ */ diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c deleted file mode 100644 index 8e035b5d733f..000000000000 --- a/sound/soc/codecs/uda134x.c +++ /dev/null @@ -1,668 +0,0 @@ -/* - * uda134x.c -- UDA134X ALSA SoC Codec driver - * - * Modifications by Christian Pellegrin <chripell@evolware.org> - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - * - * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/initval.h> - -#include <sound/uda134x.h> -#include <sound/l3.h> - -#include "uda134x.h" - - -#define POWER_OFF_ON_STANDBY 1 -/* - ALSA SOC usually puts the device in standby mode when it's not used - for sometime. If you define POWER_OFF_ON_STANDBY the driver will - turn off the ADC/DAC when this callback is invoked and turn it back - on when needed. Unfortunately this will result in a very light bump - (it can be audible only with good earphones). If this bothers you - just comment this line, you will have slightly higher power - consumption . Please note that sending the L3 command for ADC is - enough to make the bump, so it doesn't make difference if you - completely take off power from the codec. - */ - -#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 -#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) - -struct uda134x_priv { - int sysclk; - int dai_fmt; - - struct snd_pcm_substream *master_substream; - struct snd_pcm_substream *slave_substream; -}; - -/* In-data addresses are hard-coded into the reg-cache values */ -static const char uda134x_reg[UDA134X_REGS_NUM] = { - /* Extended address registers */ - 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Status, data regs */ - 0x00, 0x83, 0x00, 0x40, 0x80, 0x00, -}; - -/* - * The codec has no support for reading its registers except for peak level... - */ -static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *cache = codec->reg_cache; - - if (reg >= UDA134X_REGS_NUM) - return -1; - return cache[reg]; -} - -/* - * Write the register cache - */ -static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, unsigned int value) -{ - u8 *cache = codec->reg_cache; - - if (reg >= UDA134X_REGS_NUM) - return; - cache[reg] = value; -} - -/* - * Write to the uda134x registers - * - */ -static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - int ret; - u8 addr; - u8 data = value; - struct uda134x_platform_data *pd = codec->control_data; - - pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); - - if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unkown register: reg: %d", - __func__, reg); - return -EINVAL; - } - - uda134x_write_reg_cache(codec, reg, value); - - switch (reg) { - case UDA134X_STATUS0: - case UDA134X_STATUS1: - addr = UDA134X_STATUS_ADDR; - break; - case UDA134X_DATA000: - case UDA134X_DATA001: - case UDA134X_DATA010: - addr = UDA134X_DATA0_ADDR; - break; - case UDA134X_DATA1: - addr = UDA134X_DATA1_ADDR; - break; - default: - /* It's an extended address register */ - addr = (reg | UDA134X_EXTADDR_PREFIX); - - ret = l3_write(&pd->l3, - UDA134X_DATA0_ADDR, &addr, 1); - if (ret != 1) - return -EIO; - - addr = UDA134X_DATA0_ADDR; - data = (value | UDA134X_EXTDATA_PREFIX); - break; - } - - ret = l3_write(&pd->l3, - addr, &data, 1); - if (ret != 1) - return -EIO; - - return 0; -} - -static inline void uda134x_reset(struct snd_soc_codec *codec) -{ - u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6)); - msleep(1); - uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6)); -} - -static int uda134x_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010); - - pr_debug("%s mute: %d\n", __func__, mute); - - if (mute) - mute_reg |= (1<<2); - else - mute_reg &= ~(1<<2); - - uda134x_write(codec, UDA134X_DATA010, mute_reg & ~(1<<2)); - - return 0; -} - -static int uda134x_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - struct uda134x_priv *uda134x = codec->private_data; - struct snd_pcm_runtime *master_runtime; - - if (uda134x->master_substream) { - master_runtime = uda134x->master_substream->runtime; - - pr_debug("%s constraining to %d bits at %d\n", __func__, - master_runtime->sample_bits, - master_runtime->rate); - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate, - master_runtime->rate); - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - master_runtime->sample_bits, - master_runtime->sample_bits); - - uda134x->slave_substream = substream; - } else - uda134x->master_substream = substream; - - return 0; -} - -static void uda134x_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - struct uda134x_priv *uda134x = codec->private_data; - - if (uda134x->master_substream == substream) - uda134x->master_substream = uda134x->slave_substream; - - uda134x->slave_substream = NULL; -} - -static int uda134x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - struct uda134x_priv *uda134x = codec->private_data; - u8 hw_params; - - if (substream == uda134x->slave_substream) { - pr_debug("%s ignoring hw_params for slave substream\n", - __func__); - return 0; - } - - hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - hw_params &= STATUS0_SYSCLK_MASK; - hw_params &= STATUS0_DAIFMT_MASK; - - pr_debug("%s sysclk: %d, rate:%d\n", __func__, - uda134x->sysclk, params_rate(params)); - - /* set SYSCLK / fs ratio */ - switch (uda134x->sysclk / params_rate(params)) { - case 512: - break; - case 384: - hw_params |= (1<<4); - break; - case 256: - hw_params |= (1<<5); - break; - default: - printk(KERN_ERR "%s unsupported fs\n", __func__); - return -EINVAL; - } - - pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__, - uda134x->dai_fmt, params_format(params)); - - /* set DAI format and word length */ - switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - case SND_SOC_DAIFMT_RIGHT_J: - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - hw_params |= (1<<1); - break; - case SNDRV_PCM_FORMAT_S18_3LE: - hw_params |= (1<<2); - break; - case SNDRV_PCM_FORMAT_S20_3LE: - hw_params |= ((1<<2) | (1<<1)); - break; - default: - printk(KERN_ERR "%s unsupported format (right)\n", - __func__); - return -EINVAL; - } - break; - case SND_SOC_DAIFMT_LEFT_J: - hw_params |= (1<<3); - break; - default: - printk(KERN_ERR "%s unsupported format\n", __func__); - return -EINVAL; - } - - uda134x_write(codec, UDA134X_STATUS0, hw_params); - - return 0; -} - -static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct uda134x_priv *uda134x = codec->private_data; - - pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__, - clk_id, freq, dir); - - /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable - because the codec is slave. Of course limitations of the clock - master (the IIS controller) apply. - We'll error out on set_hw_params if it's not OK */ - if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { - uda134x->sysclk = freq; - return 0; - } - - printk(KERN_ERR "%s unsupported sysclk\n", __func__); - return -EINVAL; -} - -static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct uda134x_priv *uda134x = codec->private_data; - - pr_debug("%s fmt: %08X\n", __func__, fmt); - - /* codec supports only full slave mode */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - printk(KERN_ERR "%s unsupported slave mode\n", __func__); - return -EINVAL; - } - - /* no support for clock inversion */ - if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { - printk(KERN_ERR "%s unsupported clock inversion\n", __func__); - return -EINVAL; - } - - /* We can't setup DAI format here as it depends on the word bit num */ - /* so let's just store the value for later */ - uda134x->dai_fmt = fmt; - - return 0; -} - -static int uda134x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u8 reg; - struct uda134x_platform_data *pd = codec->control_data; - int i; - u8 *cache = codec->reg_cache; - - pr_debug("%s bias level %d\n", __func__, level); - - switch (level) { - case SND_SOC_BIAS_ON: - /* ADC, DAC on */ - reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); - uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); - break; - case SND_SOC_BIAS_PREPARE: - /* power on */ - if (pd->power) { - pd->power(1); - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++) - codec->write(codec, i, *cache++); - } - break; - case SND_SOC_BIAS_STANDBY: - /* ADC, DAC power off */ - reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); - uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); - break; - case SND_SOC_BIAS_OFF: - /* power off */ - if (pd->power) - pd->power(0); - break; - } - codec->bias_level = level; - return 0; -} - -static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1", - "Minimum2", "Maximum"}; -static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const char *uda134x_mixmode[] = {"Differential", "Analog1", - "Analog2", "Both"}; - -static const struct soc_enum uda134x_mixer_enum[] = { -SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting), -SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph), -SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode), -}; - -static const struct snd_kcontrol_new uda1341_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), -SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0), -SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1), -SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1), - -SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0), -SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), -SOC_ENUM("Input Mux", uda134x_mixer_enum[2]), - -SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0), -SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1), -SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0), - -SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0), -SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0), -SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0), -SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0), -SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0), -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static const struct snd_kcontrol_new uda1340_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), - -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static int uda134x_add_controls(struct snd_soc_codec *codec) -{ - int err, i, n; - const struct snd_kcontrol_new *ctrls; - struct uda134x_platform_data *pd = codec->control_data; - - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1344: - n = ARRAY_SIZE(uda1340_snd_controls); - ctrls = uda1340_snd_controls; - break; - case UDA134X_UDA1341: - n = ARRAY_SIZE(uda1341_snd_controls); - ctrls = uda1341_snd_controls; - break; - default: - printk(KERN_ERR "%s unkown codec type: %d", - __func__, pd->model); - return -EINVAL; - } - - for (i = 0; i < n; i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&ctrls[i], - codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -struct snd_soc_dai uda134x_dai = { - .name = "UDA134X", - /* playback capabilities */ - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* capture capabilities */ - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* pcm operations */ - .ops = { - .startup = uda134x_startup, - .shutdown = uda134x_shutdown, - .hw_params = uda134x_hw_params, - .digital_mute = uda134x_mute, - .set_sysclk = uda134x_set_dai_sysclk, - .set_fmt = uda134x_set_dai_fmt, - } -}; -EXPORT_SYMBOL(uda134x_dai); - - -static int uda134x_soc_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - struct uda134x_priv *uda134x; - void *codec_setup_data = socdev->codec_data; - int ret = -ENOMEM; - struct uda134x_platform_data *pd; - - printk(KERN_INFO "UDA134X SoC Audio Codec\n"); - - if (!codec_setup_data) { - printk(KERN_ERR "UDA134X SoC codec: " - "missing L3 bitbang function\n"); - return -ENODEV; - } - - pd = codec_setup_data; - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1341: - case UDA134X_UDA1344: - break; - default: - printk(KERN_ERR "UDA134X SoC codec: " - "unsupported model %d\n", - pd->model); - return -EINVAL; - } - - socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (socdev->codec == NULL) - return ret; - - codec = socdev->codec; - - uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); - if (uda134x == NULL) - goto priv_err; - codec->private_data = uda134x; - - codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) - goto reg_err; - - mutex_init(&codec->mutex); - - codec->reg_cache_size = sizeof(uda134x_reg); - codec->reg_cache_step = 1; - - codec->name = "UDA134X"; - codec->owner = THIS_MODULE; - codec->dai = &uda134x_dai; - codec->num_dai = 1; - codec->read = uda134x_read_reg_cache; - codec->write = uda134x_write; -#ifdef POWER_OFF_ON_STANDBY - codec->set_bias_level = uda134x_set_bias_level; -#endif - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->control_data = codec_setup_data; - - if (pd->power) - pd->power(1); - - uda134x_reset(codec); - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register pcms\n"); - goto pcm_err; - } - - ret = uda134x_add_controls(codec); - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register controls\n"); - goto pcm_err; - } - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register card\n"); - goto card_err; - } - - return 0; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); -reg_err: - kfree(codec->private_data); -priv_err: - kfree(codec); - return ret; -} - -/* power down chip */ -static int uda134x_soc_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - kfree(codec->private_data); - kfree(codec->reg_cache); - kfree(codec); - - return 0; -} - -#if defined(CONFIG_PM) -static int uda134x_soc_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int uda134x_soc_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); - return 0; -} -#else -#define uda134x_soc_suspend NULL -#define uda134x_soc_resume NULL -#endif /* CONFIG_PM */ - -struct snd_soc_codec_device soc_codec_dev_uda134x = { - .probe = uda134x_soc_probe, - .remove = uda134x_soc_remove, - .suspend = uda134x_soc_suspend, - .resume = uda134x_soc_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); - -static int __devinit uda134x_init(void) -{ - return snd_soc_register_dai(&uda134x_dai); -} -module_init(uda134x_init); - -static void __exit uda134x_exit(void) -{ - snd_soc_unregister_dai(&uda134x_dai); -} -module_exit(uda134x_exit); - -MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); -MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h deleted file mode 100644 index 94f440490b31..000000000000 --- a/sound/soc/codecs/uda134x.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _UDA134X_CODEC_H -#define _UDA134X_CODEC_H - -#define UDA134X_L3ADDR 5 -#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) -#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) -#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) - -#define UDA134X_EXTADDR_PREFIX 0xC0 -#define UDA134X_EXTDATA_PREFIX 0xE0 - -/* UDA134X registers */ -#define UDA134X_EA000 0 -#define UDA134X_EA001 1 -#define UDA134X_EA010 2 -#define UDA134X_EA011 3 -#define UDA134X_EA100 4 -#define UDA134X_EA101 5 -#define UDA134X_EA110 6 -#define UDA134X_EA111 7 -#define UDA134X_STATUS0 8 -#define UDA134X_STATUS1 9 -#define UDA134X_DATA000 10 -#define UDA134X_DATA001 11 -#define UDA134X_DATA010 12 -#define UDA134X_DATA1 13 - -#define UDA134X_REGS_NUM 14 - -#define STATUS0_DAIFMT_MASK (~(7<<1)) -#define STATUS0_SYSCLK_MASK (~(3<<4)) - -extern struct snd_soc_dai uda134x_dai; -extern struct snd_soc_codec_device soc_codec_dev_uda134x; - -#endif diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 55a99b6a68a1..a69ee72a7af5 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -407,8 +407,7 @@ static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, * when the DAI is being clocked by the CPU DAI. It's up to the * machine and cpu DAI driver to do this before we are called. */ -static int uda1380_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -440,8 +439,7 @@ static int uda1380_pcm_prepare(struct snd_pcm_substream *substream, } static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -479,8 +477,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -563,6 +560,8 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, + }, + .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -580,6 +579,8 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, + }, + .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -597,6 +598,8 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, + }, + .dai_ops = { .set_fmt = uda1380_set_dai_fmt, }, }, @@ -677,7 +680,7 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) /* uda1380 init */ uda1380_add_controls(codec); uda1380_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { pr_err("uda1380: failed to register card\n"); goto card_err; @@ -841,18 +844,6 @@ struct snd_soc_codec_device soc_codec_dev_uda1380 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); -static int __devinit uda1380_modinit(void) -{ - return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); -} -module_init(uda1380_modinit); - -static void __exit uda1380_exit(void) -{ - snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); -} -module_exit(uda1380_exit); - MODULE_AUTHOR("Giorgio Padrin"); MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index a2af04bb4e9f..d8ca2da8d634 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -463,8 +463,7 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -586,6 +585,8 @@ struct snd_soc_dai wm8510_dai = { .formats = WM8510_FORMATS,}, .ops = { .hw_params = wm8510_pcm_hw_params, + }, + .dai_ops = { .digital_mute = wm8510_mute, .set_fmt = wm8510_set_dai_fmt, .set_clkdiv = wm8510_set_dai_clkdiv, @@ -658,7 +659,7 @@ static int wm8510_init(struct snd_soc_device *socdev) wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8510_add_controls(codec); wm8510_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8510: failed to register card\n"); goto card_err; @@ -889,18 +890,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8510 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); -static int __devinit wm8510_modinit(void) -{ - return snd_soc_register_dai(&wm8510_dai); -} -module_init(wm8510_modinit); - -static void __exit wm8510_exit(void) -{ - snd_soc_unregister_dai(&wm8510_dai); -} -module_exit(wm8510_exit); - MODULE_DESCRIPTION("ASoC WM8510 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 391ec2978aed..627ebfb4209b 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -548,13 +548,13 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *dai = rtd->dai; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); + u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id); paifb &= ~WM8580_AIF_LENGTH_MASK; /* bit size */ @@ -574,7 +574,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb); + wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb); return 0; } @@ -798,6 +798,8 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, + }, + .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, @@ -816,6 +818,8 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, + }, + .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, @@ -869,7 +873,7 @@ static int wm8580_init(struct snd_soc_device *socdev) wm8580_add_controls(codec); wm8580_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8580: failed to register card\n"); goto card_err; @@ -896,85 +900,85 @@ static struct snd_soc_device *wm8580_socdev; * low = 0x1a * high = 0x1b */ +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; -static int wm8580_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static struct i2c_driver wm8580_i2c_driver; +static struct i2c_client client_template; + +static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind) { struct snd_soc_device *socdev = wm8580_socdev; + struct wm8580_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; int ret; + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } i2c_set_clientdata(i2c, codec); codec->control_data = i2c; + ret = i2c_attach_client(i2c); + if (ret < 0) { + dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr); + goto err; + } + ret = wm8580_init(socdev); - if (ret < 0) + if (ret < 0) { dev_err(&i2c->dev, "failed to initialise WM8580\n"); + goto err; + } + + return ret; + +err: + kfree(codec); + kfree(i2c); return ret; } -static int wm8580_i2c_remove(struct i2c_client *client) +static int wm8580_i2c_detach(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); + i2c_detach_client(client); kfree(codec->reg_cache); + kfree(client); return 0; } -static const struct i2c_device_id wm8580_i2c_id[] = { - { "wm8580", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); +static int wm8580_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8580_codec_probe); +} +/* corgi i2c codec control layer */ static struct i2c_driver wm8580_i2c_driver = { .driver = { .name = "WM8580 I2C Codec", .owner = THIS_MODULE, }, - .probe = wm8580_i2c_probe, - .remove = wm8580_i2c_remove, - .id_table = wm8580_i2c_id, + .attach_adapter = wm8580_i2c_attach, + .detach_client = wm8580_i2c_detach, + .command = NULL, }; -static int wm8580_add_i2c_device(struct platform_device *pdev, - const struct wm8580_setup_data *setup) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; - - ret = i2c_add_driver(&wm8580_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "wm8580", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8580_i2c_driver); - return -ENODEV; -} +static struct i2c_client client_template = { + .name = "WM8580", + .driver = &wm8580_i2c_driver, +}; #endif static int wm8580_probe(struct platform_device *pdev) @@ -1007,8 +1011,11 @@ static int wm8580_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; - ret = wm8580_add_i2c_device(pdev, setup); + ret = i2c_add_driver(&wm8580_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); } #else /* Add other interfaces here */ @@ -1027,7 +1034,6 @@ static int wm8580_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8580_i2c_driver); #endif kfree(codec->private_data); @@ -1042,18 +1048,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); -static int __devinit wm8580_modinit(void) -{ - return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); -} -module_init(wm8580_modinit); - -static void __exit wm8580_exit(void) -{ - snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); -} -module_exit(wm8580_exit); - MODULE_DESCRIPTION("ASoC WM8580 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h index 09e4422f6f2f..589ddaba21d7 100644 --- a/sound/soc/codecs/wm8580.h +++ b/sound/soc/codecs/wm8580.h @@ -29,7 +29,6 @@ #define WM8580_CLKSRC_NONE 5 struct wm8580_setup_data { - int i2c_bus; unsigned short i2c_address; }; diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c deleted file mode 100644 index d905e25b1a93..000000000000 --- a/sound/soc/codecs/wm8728.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * wm8728.c -- WM8728 ALSA SoC Audio driver - * - * Copyright 2008 Wolfson Microelectronics plc - * - * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/i2c.h> -#include <linux/platform_device.h> -#include <linux/spi/spi.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/initval.h> -#include <sound/tlv.h> - -#include "wm8728.h" - -struct snd_soc_codec_device soc_codec_dev_wm8728; - -/* - * We can't read the WM8728 register space so we cache them instead. - * Note that the defaults here aren't the physical defaults, we latch - * the volume update bits, mute the output and enable infinite zero - * detect. - */ -static const u16 wm8728_reg_defaults[] = { - 0x1ff, - 0x1ff, - 0x001, - 0x100, -}; - -static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); - return cache[reg]; -} - -static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); - cache[reg] = value; -} - -/* - * write to the WM8728 register space - */ -static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8728 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8728_write_reg_cache(codec, reg, value); - - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); - -static const struct snd_kcontrol_new wm8728_snd_controls[] = { - -SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, - 0, 255, 0, wm8728_tlv), - -SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), -}; - -static int wm8728_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8728_snd_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -/* - * DAPM controls. - */ -static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = { -SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_OUTPUT("VOUTL"), -SND_SOC_DAPM_OUTPUT("VOUTR"), -}; - -static const struct snd_soc_dapm_route intercon[] = { - {"VOUTL", NULL, "DAC"}, - {"VOUTR", NULL, "DAC"}, -}; - -static int wm8728_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets, - ARRAY_SIZE(wm8728_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - - snd_soc_dapm_new_widgets(codec); - - return 0; -} - -static int wm8728_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - - if (mute) - wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); - else - wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); - - return 0; -} - -static int wm8728_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); - - dac &= ~0x18; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - dac |= 0x10; - break; - case SNDRV_PCM_FORMAT_S24_LE: - dac |= 0x08; - break; - default: - return -EINVAL; - } - - wm8728_write(codec, WM8728_DACCTL, dac); - - return 0; -} - -static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); - - /* Currently only I2S is supported by the driver, though the - * hardware is more flexible. - */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - iface |= 1; - break; - default: - return -EINVAL; - } - - /* The hardware only support full slave mode */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - iface &= ~0x22; - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= 0x20; - iface &= ~0x02; - break; - case SND_SOC_DAIFMT_NB_IF: - iface |= 0x02; - iface &= ~0x20; - break; - case SND_SOC_DAIFMT_IB_IF: - iface |= 0x22; - break; - default: - return -EINVAL; - } - - wm8728_write(codec, WM8728_IFCTL, iface); - return 0; -} - -static int wm8728_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u16 reg; - int i; - - switch (level) { - case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: - case SND_SOC_BIAS_STANDBY: - if (codec->bias_level == SND_SOC_BIAS_OFF) { - /* Power everything up... */ - reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); - - /* ..then sync in the register cache. */ - for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) - wm8728_write(codec, i, - wm8728_read_reg_cache(codec, i)); - } - break; - - case SND_SOC_BIAS_OFF: - reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - wm8728_write(codec, WM8728_DACCTL, reg | 0x4); - break; - } - codec->bias_level = level; - return 0; -} - -#define WM8728_RATES (SNDRV_PCM_RATE_8000_192000) - -#define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) - -struct snd_soc_dai wm8728_dai = { - .name = "WM8728", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = WM8728_RATES, - .formats = WM8728_FORMATS, - }, - .ops = { - .hw_params = wm8728_hw_params, - .digital_mute = wm8728_mute, - .set_fmt = wm8728_set_dai_fmt, - } -}; -EXPORT_SYMBOL_GPL(wm8728_dai); - -static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm8728_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - wm8728_set_bias_level(codec, codec->suspend_bias_level); - - return 0; -} - -/* - * initialise the WM8728 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8728_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; - - codec->name = "WM8728"; - codec->owner = THIS_MODULE; - codec->read = wm8728_read_reg_cache; - codec->write = wm8728_write; - codec->set_bias_level = wm8728_set_bias_level; - codec->dai = &wm8728_dai; - codec->num_dai = 1; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults); - codec->reg_cache = kmemdup(wm8728_reg_defaults, - sizeof(wm8728_reg_defaults), - GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "wm8728: failed to create pcms\n"); - goto pcm_err; - } - - /* power on device */ - wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - wm8728_add_controls(codec); - wm8728_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8728: failed to register card\n"); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -static struct snd_soc_device *wm8728_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* - * WM8728 2 wire address is determined by GPIO5 - * state during powerup. - * low = 0x1a - * high = 0x1b - */ - -static int wm8728_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct snd_soc_device *socdev = wm8728_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = wm8728_init(socdev); - if (ret < 0) - pr_err("failed to initialise WM8728\n"); - - return ret; -} - -static int wm8728_i2c_remove(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); - return 0; -} - -static const struct i2c_device_id wm8728_i2c_id[] = { - { "wm8728", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); - -static struct i2c_driver wm8728_i2c_driver = { - .driver = { - .name = "WM8728 I2C Codec", - .owner = THIS_MODULE, - }, - .probe = wm8728_i2c_probe, - .remove = wm8728_i2c_remove, - .id_table = wm8728_i2c_id, -}; - -static int wm8728_add_i2c_device(struct platform_device *pdev, - const struct wm8728_setup_data *setup) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; - - ret = i2c_add_driver(&wm8728_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "wm8728", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8728_i2c_driver); - return -ENODEV; -} -#endif - -#if defined(CONFIG_SPI_MASTER) -static int __devinit wm8728_spi_probe(struct spi_device *spi) -{ - struct snd_soc_device *socdev = wm8728_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; - - codec->control_data = spi; - - ret = wm8728_init(socdev); - if (ret < 0) - dev_err(&spi->dev, "failed to initialise WM8728\n"); - - return ret; -} - -static int __devexit wm8728_spi_remove(struct spi_device *spi) -{ - return 0; -} - -static struct spi_driver wm8728_spi_driver = { - .driver = { - .name = "wm8728", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = wm8728_spi_probe, - .remove = __devexit_p(wm8728_spi_remove), -}; - -static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} -#endif /* CONFIG_SPI_MASTER */ - -static int wm8728_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8728_setup_data *setup; - struct snd_soc_codec *codec; - int ret = 0; - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - wm8728_socdev = socdev; - ret = -ENODEV; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; - ret = wm8728_add_i2c_device(pdev, setup); - } -#endif -#if defined(CONFIG_SPI_MASTER) - if (setup->spi) { - codec->hw_write = (hw_write_t)wm8728_spi_write; - ret = spi_register_driver(&wm8728_spi_driver); - if (ret != 0) - printk(KERN_ERR "can't add spi driver"); - } -#endif - - if (ret != 0) - kfree(codec); - - return ret; -} - -/* power down chip */ -static int wm8728_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&wm8728_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8728_spi_driver); -#endif - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_wm8728 = { - .probe = wm8728_probe, - .remove = wm8728_remove, - .suspend = wm8728_suspend, - .resume = wm8728_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); - -static int __devinit wm8728_modinit(void) -{ - return snd_soc_register_dai(&wm8728_dai); -} -module_init(wm8728_modinit); - -static void __exit wm8728_exit(void) -{ - snd_soc_unregister_dai(&wm8728_dai); -} -module_exit(wm8728_exit); - -MODULE_DESCRIPTION("ASoC WM8728 driver"); -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h deleted file mode 100644 index d269c132474b..000000000000 --- a/sound/soc/codecs/wm8728.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * wm8728.h -- WM8728 ASoC codec driver - * - * Copyright 2008 Wolfson Microelectronics plc - * - * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _WM8728_H -#define _WM8728_H - -#define WM8728_DACLVOL 0x00 -#define WM8728_DACRVOL 0x01 -#define WM8728_DACCTL 0x02 -#define WM8728_IFCTL 0x03 - -struct wm8728_setup_data { - int spi; - int i2c_bus; - unsigned short i2c_address; -}; - -extern struct snd_soc_dai wm8728_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm8728; - -#endif diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7b455a60d719..7f8a7e36b33e 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -264,8 +264,7 @@ static inline int get_coeff(int mclk, int rate) } static int wm8731_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -294,8 +293,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -307,8 +305,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, return 0; } -static void wm8731_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void wm8731_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -464,6 +461,8 @@ struct snd_soc_dai wm8731_dai = { .prepare = wm8731_pcm_prepare, .hw_params = wm8731_hw_params, .shutdown = wm8731_shutdown, + }, + .dai_ops = { .digital_mute = wm8731_mute, .set_sysclk = wm8731_set_dai_sysclk, .set_fmt = wm8731_set_dai_fmt, @@ -545,7 +544,7 @@ static int wm8731_init(struct snd_soc_device *socdev) wm8731_add_controls(codec); wm8731_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8731: failed to register card\n"); goto card_err; @@ -793,18 +792,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); -static int __devinit wm8731_modinit(void) -{ - return snd_soc_register_dai(&wm8731_dai); -} -module_init(wm8731_modinit); - -static void __exit wm8731_exit(void) -{ - snd_soc_unregister_dai(&wm8731_dai); -} -module_exit(wm8731_exit); - MODULE_DESCRIPTION("ASoC WM8731 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 84a6307de907..9b7296ee5b08 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -614,8 +614,7 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -710,6 +709,8 @@ struct snd_soc_dai wm8750_dai = { .formats = WM8750_FORMATS,}, .ops = { .hw_params = wm8750_pcm_hw_params, + }, + .dai_ops = { .digital_mute = wm8750_mute, .set_fmt = wm8750_set_dai_fmt, .set_sysclk = wm8750_set_dai_sysclk, @@ -818,7 +819,7 @@ static int wm8750_init(struct snd_soc_device *socdev) wm8750_add_controls(codec); wm8750_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8750: failed to register card\n"); goto card_err; @@ -1085,18 +1086,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8750 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); -static int __devinit wm8750_modinit(void) -{ - return snd_soc_register_dai(&wm8750_dai); -} -module_init(wm8750_modinit); - -static void __exit wm8750_exit(void) -{ - snd_soc_unregister_dai(&wm8750_dai); -} -module_exit(wm8750_exit); - MODULE_DESCRIPTION("ASoC WM8750 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 1caca30d0812..d426eaa22185 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -922,8 +922,7 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1156,8 +1155,7 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1325,15 +1323,16 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS}, + .formats = WM8753_FORMATS,}, .capture = { /* dummy for fast DAI switching */ .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS}, + .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params, + .hw_params = wm8753_i2s_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1h_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1357,7 +1356,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params, + .hw_params = wm8753_pcm_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1v_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1385,7 +1385,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params, + .hw_params = wm8753_pcm_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode2_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1409,7 +1410,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params, + .hw_params = wm8753_i2s_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1437,7 +1439,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params, + .hw_params = wm8753_i2s_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1605,7 +1608,7 @@ static int wm8753_init(struct snd_soc_device *socdev) wm8753_add_controls(codec); wm8753_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8753: failed to register card\n"); goto card_err; @@ -1874,18 +1877,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); -static int __devinit wm8753_modinit(void) -{ - return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); -} -module_init(wm8753_modinit); - -static void __exit wm8753_exit(void) -{ - snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); -} -module_exit(wm8753_exit); - MODULE_DESCRIPTION("ASoC WM8753 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 34e58af0c65a..3b326c9b5586 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -727,8 +727,7 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec) } static int wm8900_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1118,6 +1117,8 @@ struct snd_soc_dai wm8900_dai = { }, .ops = { .hw_params = wm8900_hw_params, + }, + .dai_ops = { .set_clkdiv = wm8900_set_dai_clkdiv, .set_pll = wm8900_set_dai_pll, .set_fmt = wm8900_set_dai_fmt, @@ -1365,7 +1366,7 @@ static int wm8900_init(struct snd_soc_device *socdev) wm8900_add_controls(codec); wm8900_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { dev_err(&i2c_client->dev, "Failed to register card\n"); goto card_err; @@ -1382,51 +1383,105 @@ priv_err: return ret; } -static struct i2c_client *wm8900_client; +static struct snd_soc_device *wm8900_socdev; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; -static int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8900_i2c_driver; +static struct i2c_client client_template; + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ +static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) { - wm8900_client = i2c; - wm8900_dai.dev = &i2c->dev; - return snd_soc_register_dai(&wm8900_dai); + struct snd_soc_device *socdev = wm8900_socdev; + struct wm8900_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + dev_err(&adap->dev, "Probe on %x\n", addr); + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + dev_err(&adap->dev, + "failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8900_init(socdev); + if (ret < 0) { + dev_err(&adap->dev, "failed to initialise WM8900\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; } -static int wm8900_i2c_remove(struct i2c_client *client) +static int wm8900_i2c_detach(struct i2c_client *client) { - snd_soc_unregister_dai(&wm8900_dai); - wm8900_dai.dev = NULL; - wm8900_client = NULL; + struct snd_soc_codec *codec = i2c_get_clientdata(client); + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); return 0; } -static const struct i2c_device_id wm8900_i2c_id[] = { - { "wm8900", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); +static int wm8900_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8900_codec_probe); +} +/* corgi i2c codec control layer */ static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "WM8900 I2C codec", .owner = THIS_MODULE, }, - .probe = wm8900_i2c_probe, - .remove = wm8900_i2c_remove, - .id_table = wm8900_i2c_id, + .attach_adapter = wm8900_i2c_attach, + .detach_client = wm8900_i2c_detach, + .command = NULL, }; +static struct i2c_client client_template = { + .name = "WM8900", + .driver = &wm8900_i2c_driver, +}; +#endif + static int wm8900_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8900_setup_data *setup; struct snd_soc_codec *codec; int ret = 0; - if (!wm8900_client) { - dev_err(&pdev->dev, "I2C client not yet instantiated\n"); - return -ENODEV; - } + dev_info(&pdev->dev, "WM8900 Audio Codec\n"); + setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; @@ -1439,13 +1494,18 @@ static int wm8900_probe(struct platform_device *pdev) codec->set_bias_level = wm8900_set_bias_level; - codec->hw_write = (hw_write_t)i2c_master_send; - codec->control_data = wm8900_client; - - ret = wm8900_init(socdev); - if (ret != 0) - kfree(codec); - + wm8900_socdev = socdev; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8900_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else +#error Non-I2C interfaces not yet supported +#endif return ret; } @@ -1460,6 +1520,9 @@ static int wm8900_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8900_i2c_driver); +#endif kfree(codec); return 0; @@ -1473,18 +1536,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8900 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); -static int __devinit wm8900_modinit(void) -{ - return i2c_add_driver(&wm8900_i2c_driver); -} -module_init(wm8900_modinit); - -static void __exit wm8900_exit(void) -{ - i2c_del_driver(&wm8900_i2c_driver); -} -module_exit(wm8900_exit); - MODULE_DESCRIPTION("ASoC WM8900 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h index 2249a446ad37..ba450d99e902 100644 --- a/sound/soc/codecs/wm8900.h +++ b/sound/soc/codecs/wm8900.h @@ -55,7 +55,6 @@ #define WM8900_ struct wm8900_setup_data { - int i2c_bus; unsigned short i2c_address; }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 5d8fe7e1571e..ce40d7877605 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -773,14 +773,14 @@ static const struct snd_kcontrol_new left_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 0, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), }; static const struct snd_kcontrol_new right_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 0, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), }; static const struct snd_kcontrol_new left_speaker_mixer[] = { @@ -788,7 +788,7 @@ SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, - 0, 1, 0), + 1, 1, 0), }; static const struct snd_kcontrol_new right_speaker_mixer[] = { @@ -797,7 +797,7 @@ SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, - 0, 1, 0), + 1, 1, 0), }; static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = { @@ -1257,8 +1257,7 @@ static struct { { 0, 0 }, }; -static int wm8903_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int wm8903_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1299,8 +1298,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream, return 0; } -static void wm8903_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void wm8903_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1319,8 +1317,7 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream, } static int wm8903_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1518,6 +1515,8 @@ struct snd_soc_dai wm8903_dai = { .startup = wm8903_startup, .shutdown = wm8903_shutdown, .hw_params = wm8903_hw_params, + }, + .dai_ops = { .digital_mute = wm8903_digital_mute, .set_fmt = wm8903_set_dai_fmt, .set_sysclk = wm8903_set_dai_sysclk @@ -1648,7 +1647,7 @@ static int wm8903_init(struct snd_soc_device *socdev) wm8903_add_controls(codec); wm8903_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { dev_err(&i2c->dev, "wm8903: failed to register card\n"); goto card_err; @@ -1809,18 +1808,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8903 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); -static int __devinit wm8903_modinit(void) -{ - return snd_soc_register_dai(&wm8903_dai); -} -module_init(wm8903_modinit); - -static void __exit wm8903_exit(void) -{ - snd_soc_unregister_dai(&wm8903_dai); -} -module_exit(wm8903_exit); - MODULE_DESCRIPTION("ASoC WM8903 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 2979fc4f44f1..f41a578ddd4f 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -541,8 +541,7 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -635,6 +634,8 @@ struct snd_soc_dai wm8971_dai = { .formats = WM8971_FORMATS,}, .ops = { .hw_params = wm8971_pcm_hw_params, + }, + .dai_ops = { .digital_mute = wm8971_mute, .set_fmt = wm8971_set_dai_fmt, .set_sysclk = wm8971_set_dai_sysclk, @@ -747,7 +748,7 @@ static int wm8971_init(struct snd_soc_device *socdev) wm8971_add_controls(codec); wm8971_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8971: failed to register card\n"); goto card_err; @@ -935,18 +936,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8971 = { EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); -static int __devinit wm8971_modinit(void) -{ - return snd_soc_register_dai(&wm8971_dai); -} -module_init(wm8971_modinit); - -static void __exit wm8971_exit(void) -{ - snd_soc_unregister_dai(&wm8971_dai); -} -module_exit(wm8971_exit); - MODULE_DESCRIPTION("ASoC WM8971 driver"); MODULE_AUTHOR("Lab126"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 53e71aafe6c6..572d22b0880b 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -106,7 +106,6 @@ static const u16 wm8990_reg[] = { 0x0008, /* R60 - PLL1 */ 0x0031, /* R61 - PLL2 */ 0x0026, /* R62 - PLL3 */ - 0x0000, /* R63 - Driver internal */ }; /* @@ -127,9 +126,10 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u16 *cache = codec->reg_cache; + BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); - /* Reset register and reserved registers are uncached */ - if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1) + /* Reset register is uncached */ + if (reg == 0) return; cache[reg] = value; @@ -1172,8 +1172,7 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8990_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1223,14 +1222,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: break; - case SND_SOC_BIAS_PREPARE: - /* VMID=2*50k */ - val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & - ~WM8990_VMID_MODE_MASK; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); break; - case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable all output discharge bits */ @@ -1279,17 +1272,10 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); + } else { + /* ON -> standby */ - /* Enable workaround for ADC clocking issue. */ - wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); - wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); - wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); } - - /* VMID=2*250k */ - val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & - ~WM8990_VMID_MODE_MASK; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); break; case SND_SOC_BIAS_OFF: @@ -1363,7 +1349,8 @@ struct snd_soc_dai wm8990_dai = { .rates = WM8990_RATES, .formats = WM8990_FORMATS,}, .ops = { - .hw_params = wm8990_hw_params, + .hw_params = wm8990_hw_params,}, + .dai_ops = { .digital_mute = wm8990_mute, .set_fmt = wm8990_set_dai_fmt, .set_clkdiv = wm8990_set_dai_clkdiv, @@ -1462,7 +1449,7 @@ static int wm8990_init(struct snd_soc_device *socdev) wm8990_add_controls(codec); wm8990_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8990: failed to register card\n"); goto card_err; @@ -1643,18 +1630,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); -static int __devinit wm8990_modinit(void) -{ - return snd_soc_register_dai(&wm8990_dai); -} -module_init(wm8990_modinit); - -static void __exit wm8990_exit(void) -{ - snd_soc_unregister_dai(&wm8990_dai); -} -module_exit(wm8990_exit); - MODULE_DESCRIPTION("ASoC WM8990 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 7114ddc88b4b..0e192f3b0788 100644 --- a/sound/soc/codecs/wm8990.h +++ b/sound/soc/codecs/wm8990.h @@ -80,8 +80,8 @@ #define WM8990_PLL3 0x3E #define WM8990_INTDRIVBITS 0x3F -#define WM8990_EXT_ACCESS_ENA 0x75 -#define WM8990_EXT_CTL1 0x7a +#define WM8990_REGISTER_COUNT 60 +#define WM8990_MAX_REGISTER 0x3F /* * Field Definitions. diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index af83d629078a..ffb471e420e2 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -487,8 +487,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } -static int ac97_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -508,8 +507,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_aux_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -535,7 +533,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9712_dai[] = { { .name = "AC97 HiFi", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97_BUS, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, @@ -690,7 +688,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) ret = wm9712_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n"); + printk(KERN_ERR "AC97 link error\n"); goto reset_err; } @@ -700,7 +698,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm9712_add_controls(codec); wm9712_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm9712: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index f3ca8aaf0139..945b32ed9884 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -928,10 +928,11 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3; switch (params_format(params)) { @@ -953,10 +954,11 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; u16 status; /* Gracefully shut down the voice interface. */ @@ -967,11 +969,12 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, ac97_write(codec, AC97_EXTENDED_MID, status); } -static int ac97_hifi_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_hifi_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; int reg; u16 vra; @@ -986,11 +989,12 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream, return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_aux_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; u16 vra, xsle; vra = ac97_read(codec, AC97_EXTENDED_STATUS); @@ -1024,7 +1028,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9713_dai[] = { { .name = "AC97 HiFi", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97_BUS, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, @@ -1038,7 +1042,8 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_hifi_prepare, + .prepare = ac97_hifi_prepare,}, + .dai_ops = { .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1051,7 +1056,8 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_aux_prepare, + .prepare = ac97_aux_prepare,}, + .dai_ops = { .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1071,7 +1077,8 @@ struct snd_soc_dai wm9713_dai[] = { .formats = WM9713_PCM_FORMATS,}, .ops = { .hw_params = wm9713_pcm_hw_params, - .shutdown = wm9713_voiceshutdown, + .shutdown = wm9713_voiceshutdown,}, + .dai_ops = { .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll, .set_fmt = wm9713_set_dai_fmt, @@ -1090,8 +1097,6 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) } soc_ac97_ops.reset(codec->ac97); - if (soc_ac97_ops.warm_reset) - soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, 0) != wm9713_reg[0]) return -EIO; return 0; @@ -1235,7 +1240,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_reset(codec, 0); ret = wm9713_reset(codec, 1); if (ret < 0) { - printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); + printk(KERN_ERR "AC97 link error\n"); goto reset_err; } @@ -1247,7 +1252,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_add_controls(codec); wm9713_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) goto reset_err; return 0; @@ -1283,6 +1288,7 @@ static int wm9713_soc_remove(struct platform_device *pdev) snd_soc_free_ac97_codec(codec); kfree(codec->private_data); kfree(codec->reg_cache); + kfree(codec->dai); kfree(codec); return 0; } diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index b502741692d6..8f7e33834902 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -17,13 +17,3 @@ config SND_DAVINCI_SOC_EVM help Say Y if you want to add support for SoC audio on TI DaVinci EVM platform. - -config SND_DAVINCI_SOC_SFFSDR - tristate "SoC Audio support for SFFSDR" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR - select SND_DAVINCI_SOC_I2S - select SND_SOC_PCM3008 - select SFFSDR_FPGA - help - Say Y if you want to add support for SoC audio on - Lyrtech SFFSDR board. diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index ca8bae1fc3f6..ca772e5b4637 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -7,7 +7,5 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o # DAVINCI Machine Support snd-soc-evm-objs := davinci-evm.o -snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o -obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index d87b91179cc8..9e6062cd6b59 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -128,9 +128,8 @@ static struct snd_soc_dai_link evm_dai = { }; /* davinci-evm audio machine driver */ -static struct snd_soc_card snd_soc_card_evm = { +static struct snd_soc_machine snd_soc_machine_evm = { .name = "DaVinci EVM", - .platform = &davinci_soc_platform, .dai_link = &evm_dai, .num_links = 1, }; @@ -143,7 +142,8 @@ static struct aic3x_setup_data evm_aic3x_setup = { /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { - .card = &snd_soc_card_evm, + .machine = &snd_soc_machine_evm, + .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &evm_aic3x_setup, }; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d89fc2f009ab..abb5fedb0b1e 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -59,7 +59,6 @@ #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) -#define DAVINCI_MCBSP_PCR_SCLKME (1 << 7) #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) @@ -111,59 +110,16 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_platform *platform = socdev->card->platform; u32 w; - int ret; /* Start the sample generator and enable transmitter/receiver */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* Stop the DMA to avoid data loss */ - /* while the transmitter is out of reset to handle XSYNCERR */ - if (platform->pcm_ops->trigger) { - ret = platform->pcm_ops->trigger(substream, - SNDRV_PCM_TRIGGER_STOP); - if (ret < 0) - printk(KERN_DEBUG "Playback DMA stop failed\n"); - } - - /* Enable the transmitter */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - /* wait for any unexpected frame sync error to occur */ - udelay(100); - - /* Disable the transmitter to clear any outstanding XSYNCERR */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - /* Restart the DMA */ - if (platform->pcm_ops->trigger) { - ret = platform->pcm_ops->trigger(substream, - SNDRV_PCM_TRIGGER_START); - if (ret < 0) - printk(KERN_DEBUG "Playback DMA start failed\n"); - } - /* Enable the transmitter */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - } else { - - /* Enable the reciever */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + else MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - } - + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); /* Start frame sync */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); @@ -188,8 +144,7 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); } -static int davinci_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int davinci_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -216,16 +171,6 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, DAVINCI_MCBSP_SRGR_FSGM); break; - case SND_SOC_DAIFMT_CBM_CFS: - /* McBSP CLKR pin is the input for the Sample Rate Generator. - * McBSP FSR and FSX are driven by the Sample Rate Generator. */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, - DAVINCI_MCBSP_PCR_SCLKME | - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, - DAVINCI_MCBSP_SRGR_FSGM); - break; case SND_SOC_DAIFMT_CBM_CFM: davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); break; @@ -260,34 +205,11 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(0)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(0) | - DAVINCI_MCBSP_XCR_XFIG); - break; - case SND_SOC_DAIFMT_I2S: - default: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(1)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(1) | - DAVINCI_MCBSP_XCR_XFIG); - break; - } - return 0; } static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; @@ -297,14 +219,17 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, u32 w; /* general line settings */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - } else { - w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - } + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, + DAVINCI_MCBSP_SPCR_RINTM(3) | + DAVINCI_MCBSP_SPCR_XINTM(3) | + DAVINCI_MCBSP_SPCR_FREE); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, + DAVINCI_MCBSP_RCR_RFRLEN1(1) | + DAVINCI_MCBSP_RCR_RDATDLY(1)); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, + DAVINCI_MCBSP_XCR_XFRLEN1(1) | + DAVINCI_MCBSP_XCR_XDATDLY(1) | + DAVINCI_MCBSP_XCR_XFIG); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); @@ -335,24 +260,20 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); - } else { - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); - } return 0; } -static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int ret = 0; @@ -378,8 +299,8 @@ static int davinci_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea; struct evm_snd_platform_data *pdata; @@ -440,8 +361,8 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev = cpu_dai->private_data; struct resource *mem; @@ -460,6 +381,7 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai davinci_i2s_dai = { .name = "davinci-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .playback = { @@ -475,24 +397,13 @@ struct snd_soc_dai davinci_i2s_dai = { .ops = { .startup = davinci_i2s_startup, .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params, + .hw_params = davinci_i2s_hw_params,}, + .dai_ops = { .set_fmt = davinci_i2s_set_dai_fmt, }, }; EXPORT_SYMBOL_GPL(davinci_i2s_dai); -static int __devinit davinci_i2s_init(void) -{ - return snd_soc_register_dai(&davinci_i2s_dai); -} -module_init(davinci_i2s_init); - -static void __exit davinci_i2s_exit(void) -{ - snd_soc_unregister_dai(&davinci_i2s_dai); -} -module_exit(davinci_i2s_exit); - MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index f1b6e02d24ed..76feaa657375 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -384,18 +384,6 @@ struct snd_soc_platform davinci_soc_platform = { }; EXPORT_SYMBOL_GPL(davinci_soc_platform); -static int __devinit davinci_soc_platform_init(void) -{ - return snd_soc_register_platform(&davinci_soc_platform); -} -module_init(davinci_soc_platform_init); - -static void __exit davinci_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&davinci_soc_platform); -} -module_exit(davinci_soc_platform_exit); - MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c deleted file mode 100644 index f67579d52765..000000000000 --- a/sound/soc/davinci/davinci-sffsdr.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * ASoC driver for Lyrtech SFFSDR board. - * - * Author: Hugo Villeneuve - * Copyright (C) 2008 Lyrtech inc - * - * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow: - * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/dma.h> -#include <asm/plat-sffsdr/sffsdr-fpga.h> - -#include <mach/mcbsp.h> -#include <mach/edma.h> - -#include "../codecs/pcm3008.h" -#include "davinci-pcm.h" -#include "davinci-i2s.h" - -static int sffsdr_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int fs; - int ret = 0; - - /* Set cpu DAI configuration: - * CLKX and CLKR are the inputs for the Sample Rate Generator. - * FSX and FSR are outputs, driven by the sample Rate Generator. */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_RIGHT_J | - SND_SOC_DAIFMT_CBM_CFS | - SND_SOC_DAIFMT_IB_NF); - if (ret < 0) - return ret; - - /* Fsref can be 32000, 44100 or 48000. */ - fs = params_rate(params); - - pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); - - return sffsdr_fpga_set_codec_fs(fs); -} - -static struct snd_soc_ops sffsdr_ops = { - .hw_params = sffsdr_hw_params, -}; - -/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sffsdr_dai = { - .name = "PCM3008", /* Codec name */ - .stream_name = "PCM3008 HiFi", - .cpu_dai = &davinci_i2s_dai, - .codec_dai = &pcm3008_dai, - .ops = &sffsdr_ops, -}; - -/* davinci-sffsdr audio machine driver */ -static struct snd_soc_card snd_soc_sffsdr = { - .name = "DaVinci SFFSDR", - .platform = &davinci_soc_platform, - .dai_link = &sffsdr_dai, - .num_links = 1, -}; - -/* sffsdr audio private data */ -static struct pcm3008_setup_data sffsdr_pcm3008_setup = { - .dem0_pin = GPIO(45), - .dem1_pin = GPIO(46), - .pdad_pin = GPIO(47), - .pdda_pin = GPIO(38), -}; - -/* sffsdr audio subsystem */ -static struct snd_soc_device sffsdr_snd_devdata = { - .card = &snd_soc_sffsdr, - .codec_dev = &soc_codec_dev_pcm3008, - .codec_data = &sffsdr_pcm3008_setup, -}; - -static struct resource sffsdr_snd_resources[] = { - { - .start = DAVINCI_MCBSP_BASE, - .end = DAVINCI_MCBSP_BASE + SZ_8K - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct evm_snd_platform_data sffsdr_snd_data = { - .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, - .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, -}; - -static struct platform_device *sffsdr_snd_device; - -static int __init sffsdr_init(void) -{ - int ret; - - sffsdr_snd_device = platform_device_alloc("soc-audio", 0); - if (!sffsdr_snd_device) { - printk(KERN_ERR "platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); - sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; - sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data; - - ret = platform_device_add_resources(sffsdr_snd_device, - sffsdr_snd_resources, - ARRAY_SIZE(sffsdr_snd_resources)); - if (ret) { - printk(KERN_ERR "platform device add ressources failed\n"); - goto error; - } - - ret = platform_device_add(sffsdr_snd_device); - if (ret) - goto error; - - return ret; - -error: - platform_device_put(sffsdr_snd_device); - return ret; -} - -static void __exit sffsdr_exit(void) -{ - platform_device_unregister(sffsdr_snd_device); -} - -module_init(sffsdr_init); -module_exit(sffsdr_exit); - -MODULE_AUTHOR("Hugo Villeneuve"); -MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 95c12b26fe37..8d73edc56102 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -20,7 +20,7 @@ config SND_SOC_MPC8610_HPCD config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" - depends on PPC_MPC52xx && PPC_BESTCOMM + depends on SND_SOC && PPC_MPC52xx && PPC_BESTCOMM select SND_SOC_OF_SIMPLE select PPC_BESTCOMM_GEN_BD help diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 646c807163ab..d2d3da9729f2 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -284,7 +284,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * fsl_dma_new: initialize this PCM driver. * * This function is called when the codec driver calls snd_soc_new_pcms(), - * once for each .dai_link in the machine driver's snd_soc_card + * once for each .dai_link in the machine driver's snd_soc_machine * structure. */ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, @@ -853,18 +853,6 @@ int fsl_dma_configure(struct fsl_dma_info *dma_info) } EXPORT_SYMBOL_GPL(fsl_dma_configure); -static int __devinit fsl_soc_platform_init(void) -{ - return snd_soc_register_platform(&fsl_soc_platform); -} -module_init(fsl_soc_platform_init); - -static void __exit fsl_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&fsl_soc_platform); -} -module_exit(fsl_soc_platform_exit); - MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c6d6eb71dc1d..157a7895ffa1 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -266,8 +266,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) * If this is the first stream open, then grab the IRQ and program most of * the SSI registers. */ -static int fsl_ssi_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int fsl_ssi_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -412,8 +411,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the * clock master. */ -static int fsl_ssi_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int fsl_ssi_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -443,8 +441,7 @@ static int fsl_ssi_prepare(struct snd_pcm_substream *substream, * The DMA channel is in external master start and pause mode, which * means the SSI completely controls the flow of data. */ -static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -493,8 +490,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, * * Shutdown the SSI if there are no other substreams open. */ -static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -582,6 +578,8 @@ static struct snd_soc_dai fsl_ssi_dai_template = { .prepare = fsl_ssi_prepare, .shutdown = fsl_ssi_shutdown, .trigger = fsl_ssi_trigger, + }, + .dai_ops = { .set_sysclk = fsl_ssi_set_sysclk, .set_fmt = fsl_ssi_set_fmt, }, @@ -673,14 +671,6 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) fsl_ssi_dai->private_data = ssi_private; fsl_ssi_dai->name = ssi_private->name; fsl_ssi_dai->id = ssi_info->id; - fsl_ssi_dai->dev = ssi_info->dev; - - ret = snd_soc_register_dai(fsl_ssi_dai); - if (ret != 0) { - dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret); - kfree(fsl_ssi_dai); - return NULL; - } return fsl_ssi_dai; } @@ -698,8 +688,6 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) device_remove_file(ssi_private->dev, &ssi_private->dev_attr); - snd_soc_unregister_dai(&ssi_private->cpu_dai); - kfree(ssi_private); } EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 9eb1ce185bd0..94a02eaa4825 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -187,8 +187,7 @@ static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) * If this is the first stream open, then grab the IRQ and program most of * the PSC registers. */ -static int psc_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int psc_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -221,8 +220,7 @@ static int psc_i2s_startup(struct snd_pcm_substream *substream, } static int psc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -258,8 +256,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int psc_i2s_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int psc_i2s_hw_free(struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; @@ -271,8 +268,7 @@ static int psc_i2s_hw_free(struct snd_pcm_substream *substream, * This function is called by ALSA to start, stop, pause, and resume the DMA * transfer of data. */ -static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -387,8 +383,7 @@ static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, * * Shutdown the PSC if there are no other substreams open. */ -static void psc_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void psc_i2s_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -469,6 +464,7 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) * psc_i2s_dai_template: template CPU Digital Audio Interface */ static struct snd_soc_dai psc_i2s_dai_template = { + .type = SND_SOC_DAI_I2S, .playback = { .channels_min = 2, .channels_max = 2, @@ -487,6 +483,8 @@ static struct snd_soc_dai psc_i2s_dai_template = { .hw_free = psc_i2s_hw_free, .shutdown = psc_i2s_shutdown, .trigger = psc_i2s_trigger, + }, + .dai_ops = { .set_sysclk = psc_i2s_set_sysclk, .set_fmt = psc_i2s_set_fmt, }, @@ -828,8 +826,6 @@ static int __devinit psc_i2s_of_probe(struct of_device *op, if (rc) dev_info(psc_i2s->dev, "error creating sysfs files\n"); - snd_soc_register_platform(&psc_i2s_pcm_soc_platform); - /* Tell the ASoC OF helpers about it */ of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, &psc_i2s->dai); @@ -843,8 +839,6 @@ static int __devexit psc_i2s_of_remove(struct of_device *op) dev_dbg(&op->dev, "psc_i2s_remove()\n"); - snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform); - bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index bcec3f60bad9..94f89debde1f 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -29,7 +29,7 @@ struct mpc8610_hpcd_data { struct snd_soc_device sound_devdata; struct snd_soc_dai_link dai; - struct snd_soc_card machine; + struct snd_soc_machine machine; unsigned int dai_format; unsigned int codec_clk_direction; unsigned int cpu_clk_direction; @@ -185,7 +185,7 @@ static struct snd_soc_ops mpc8610_hpcd_ops = { /** * mpc8610_hpcd_machine: ASoC machine data */ -static struct snd_soc_card mpc8610_hpcd_machine = { +static struct snd_soc_machine mpc8610_hpcd_machine = { .probe = mpc8610_hpcd_machine_probe, .remove = mpc8610_hpcd_machine_remove, .name = "MPC8610 HPCD", @@ -465,9 +465,9 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, goto error; } - machine_data->sound_devdata.card = &mpc8610_hpcd_machine; + machine_data->sound_devdata.machine = &mpc8610_hpcd_machine; machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; - machine_data->machine.platform = &fsl_soc_platform; + machine_data->sound_devdata.platform = &fsl_soc_platform; sound_device->dev.platform_data = machine_data; diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c index 8bc5cd9e972f..0382fdac51cd 100644 --- a/sound/soc/fsl/soc-of-simple.c +++ b/sound/soc/fsl/soc-of-simple.c @@ -31,7 +31,7 @@ struct of_snd_soc_device { int id; struct list_head list; struct snd_soc_device device; - struct snd_soc_card card; + struct snd_soc_machine machine; struct snd_soc_dai_link dai_link; struct platform_device *pdev; struct device_node *platform_node; @@ -58,9 +58,9 @@ of_snd_soc_get_device(struct device_node *codec_node) /* Initialize the structure and add it to the global list */ of_soc->codec_node = codec_node; of_soc->id = of_snd_soc_next_index++; - of_soc->card.dai_link = &of_soc->dai_link; - of_soc->card.num_links = 1; - of_soc->device.card = &of_soc->card; + of_soc->machine.dai_link = &of_soc->dai_link; + of_soc->machine.num_links = 1; + of_soc->device.machine = &of_soc->machine; of_soc->dai_link.ops = &of_snd_soc_ops; list_add(&of_soc->list, &of_snd_soc_device_list); @@ -158,8 +158,8 @@ int of_snd_soc_register_platform(struct snd_soc_platform *platform, of_soc->platform_node = node; of_soc->dai_link.cpu_dai = cpu_dai; - of_soc->card.platform = platform; - of_soc->card.name = of_soc->dai_link.cpu_dai->name; + of_soc->device.platform = platform; + of_soc->machine.name = of_soc->dai_link.cpu_dai->name; /* Now try to register the SoC device */ of_snd_soc_register_device(of_soc); diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a7b1d77b2105..8b7766b998d7 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -1,6 +1,6 @@ config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" - depends on ARCH_OMAP + depends on ARCH_OMAP && SND_SOC config SND_OMAP_SOC_MCBSP tristate @@ -21,36 +21,3 @@ config SND_OMAP_SOC_OSK5912 select SND_SOC_TLV320AIC23 help Say Y if you want to add support for SoC audio on osk5912. - -config SND_OMAP_SOC_OVERO - tristate "SoC Audio support for Gumstix Overo" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the Gumstix Overo. - -config SND_OMAP_SOC_OMAP2EVM - tristate "SoC Audio support for OMAP2EVM board" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the omap2evm board. - -config SND_OMAP_SOC_SDP3430 - tristate "SoC Audio support for Texas Instruments SDP3430" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on Texas Instruments - SDP3430. - -config SND_OMAP_SOC_OMAP3_PANDORA - tristate "SoC Audio support for OMAP3 Pandora" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the OMAP3 Pandora. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 76fedd96e365..e09d1f297f64 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -8,14 +8,6 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o # OMAP Machine Support snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o -snd-soc-overo-objs := overo.o -snd-soc-omap2evm-objs := omap2evm.o -snd-soc-sdp3430-objs := sdp3430.o -snd-soc-omap3pandora-objs := omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o -obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o -obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o -obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 25593fee9121..fae3ad36e0bf 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -70,13 +70,9 @@ static void n810_ext_control(struct snd_soc_codec *codec) static int n810_startup(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->socdev->codec; - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); - n810_ext_control(codec); return clk_enable(sys_clkout2); } @@ -286,9 +282,8 @@ static struct snd_soc_dai_link n810_dai = { }; /* Audio machine driver */ -static struct snd_soc_card snd_soc_n810 = { +static struct snd_soc_machine snd_soc_machine_n810 = { .name = "N810", - .platform = &omap_soc_platform, .dai_link = &n810_dai, .num_links = 1, }; @@ -303,7 +298,8 @@ static struct aic3x_setup_data n810_aic33_setup = { /* Audio subsystem */ static struct snd_soc_device n810_snd_devdata = { - .card = &snd_soc_n810, + .machine = &snd_soc_machine_n810, + .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &n810_aic33_setup, }; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 41cab2034163..8485a8a9d0ff 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -36,7 +36,9 @@ #include "omap-mcbsp.h" #include "omap-pcm.h" -#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) +#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_KNOT) struct omap_mcbsp_data { unsigned int bus_id; @@ -138,8 +140,7 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { static const unsigned long omap34xx_mcbsp_port[][2] = {}; #endif -static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -152,8 +153,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, return err; } -static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -165,8 +165,7 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, } } -static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -195,15 +194,14 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, } static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen, channels; + int wlen; unsigned long port; if (cpu_class_is_omap1()) { @@ -232,17 +230,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } - channels = params_channels(params); - switch (channels) { + switch (params_channels(params)) { case 2: - /* Use dual-phase frames */ - regs->rcr2 |= RPHASE; - regs->xcr2 |= XPHASE; - case 1: - /* Set 1 word per (McBSP) frame */ - regs->rcr2 |= RFRLEN2(1 - 1); + /* Set 1 word per (McBPSP) frame and use dual-phase frames */ + regs->rcr2 |= RFRLEN2(1 - 1) | RPHASE; regs->rcr1 |= RFRLEN1(1 - 1); - regs->xcr2 |= XFRLEN2(1 - 1); + regs->xcr2 |= XFRLEN2(1 - 1) | XPHASE; regs->xcr1 |= XFRLEN1(1 - 1); break; default: @@ -271,8 +264,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->srgr1 |= FWID(wlen - 1); break; case SND_SOC_DAIFMT_DSP_A: - regs->srgr2 |= FPER(wlen * channels - 1); - regs->srgr1 |= FWID(wlen * channels - 2); + regs->srgr2 |= FPER(wlen * 2 - 1); + regs->srgr1 |= FWID(wlen * 2 - 2); break; } @@ -459,16 +452,17 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, #define OMAP_MCBSP_DAI_BUILDER(link_id) \ { \ - .name = "omap-mcbsp-dai-"#link_id, \ + .name = "omap-mcbsp-dai-(link_id)", \ .id = (link_id), \ + .type = SND_SOC_DAI_I2S, \ .playback = { \ - .channels_min = 1, \ + .channels_min = 2, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ - .channels_min = 1, \ + .channels_min = 2, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ @@ -478,6 +472,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, .shutdown = omap_mcbsp_dai_shutdown, \ .trigger = omap_mcbsp_dai_trigger, \ .hw_params = omap_mcbsp_dai_hw_params, \ + }, \ + .dai_ops = { \ .set_fmt = omap_mcbsp_dai_set_dai_fmt, \ .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \ @@ -499,19 +495,6 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); -static int __devinit omap_mcbsp_init(void) -{ - return snd_soc_register_dais(omap_mcbsp_dai, - ARRAY_SIZE(omap_mcbsp_dai)); -} -module_init(omap_mcbsp_init); - -static void __exit omap_mcbsp_exit(void) -{ - snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); -} -module_exit(omap_mcbsp_exit); - MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 9940de296316..e9084fdd2082 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -354,18 +354,6 @@ struct snd_soc_platform omap_soc_platform = { }; EXPORT_SYMBOL_GPL(omap_soc_platform); -static int __devinit omap_soc_platform_init(void) -{ - return snd_soc_register_platform(&omap_soc_platform); -} -module_init(omap_soc_platform_init); - -static void __exit omap_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&omap_soc_platform); -} -module_exit(omap_soc_platform_exit); - MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); MODULE_DESCRIPTION("OMAP PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c deleted file mode 100644 index 0c2322dcf02a..000000000000 --- a/sound/soc/omap/omap2evm.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * omap2evm.c -- SoC audio machine driver for omap2evm board - * - * Author: Arun KS <arunks@mistralsolutions.com> - * - * Based on sound/soc/omap/overo.c by Steve Sakoman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int omap2evm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops omap2evm_ops = { - .hw_params = omap2evm_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap2evm_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &omap2evm_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap2evm = { - .name = "omap2evm", - .platform = &omap_soc_platform, - .dai_link = &omap2evm_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device omap2evm_snd_devdata = { - .card = &snd_soc_omap2evm, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *omap2evm_snd_device; - -static int __init omap2evm_soc_init(void) -{ - int ret; - - if (!machine_is_omap2evm()) { - pr_debug("Not omap2evm!\n"); - return -ENODEV; - } - printk(KERN_INFO "omap2evm SoC init\n"); - - omap2evm_snd_device = platform_device_alloc("soc-audio", -1); - if (!omap2evm_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata); - omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev; - *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(omap2evm_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(omap2evm_snd_device); - - return ret; -} -module_init(omap2evm_soc_init); - -static void __exit omap2evm_soc_exit(void) -{ - platform_device_unregister(omap2evm_snd_device); -} -module_exit(omap2evm_soc_exit); - -MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); -MODULE_DESCRIPTION("ALSA SoC omap2evm"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c deleted file mode 100644 index fd24a4acd2f5..000000000000 --- a/sound/soc/omap/omap3beagle.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * omap3beagle.c -- SoC audio for OMAP3 Beagle - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int omap3beagle_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops omap3beagle_ops = { - .hw_params = omap3beagle_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3beagle_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &omap3beagle_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap3beagle = { - .name = "omap3beagle", - .platform = &omap_soc_platform, - .dai_link = &omap3beagle_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device omap3beagle_snd_devdata = { - .card = &snd_soc_omap3beagle, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *omap3beagle_snd_device; - -static int __init omap3beagle_soc_init(void) -{ - int ret; - - if (!machine_is_omap3_beagle()) { - pr_debug("Not OMAP3 Beagle!\n"); - return -ENODEV; - } - pr_info("OMAP3 Beagle SoC init\n"); - - omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); - if (!omap3beagle_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata); - omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev; - *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(omap3beagle_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(omap3beagle_snd_device); - - return ret; -} - -static void __exit omap3beagle_soc_exit(void) -{ - platform_device_unregister(omap3beagle_snd_device); -} - -module_init(omap3beagle_soc_init); -module_exit(omap3beagle_soc_exit); - -MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); -MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c deleted file mode 100644 index bd91594496b1..000000000000 --- a/sound/soc/omap/omap3pandora.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * omap3pandora.c -- SoC audio for Pandora Handheld Console - * - * Author: Gražvydas Ignotas <notasas@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> -#include <linux/delay.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -#define OMAP3_PANDORA_DAC_POWER_GPIO 118 -#define OMAP3_PANDORA_AMP_POWER_GPIO 14 - -#define PREFIX "ASoC omap3pandora: " - -static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, - struct snd_soc_dai *cpu_dai, unsigned int fmt) -{ - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt); - if (ret < 0) { - pr_err(PREFIX "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret < 0) { - pr_err(PREFIX "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - pr_err(PREFIX "can't set codec system clock\n"); - return ret; - } - - /* Set McBSP clock to external */ - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0, - SND_SOC_CLOCK_IN); - if (ret < 0) { - pr_err(PREFIX "can't set cpu system clock\n"); - return ret; - } - - ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8); - if (ret < 0) { - pr_err(PREFIX "can't set SRG clock divider\n"); - return ret; - } - - return 0; -} - -static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFS); -} - -static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); -} - -static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - if (SND_SOC_DAPM_EVENT_ON(event)) { - gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); - gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); - } else { - gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); - mdelay(1); - gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); - } - - return 0; -} - -/* - * Audio paths on Pandora board: - * - * |O| ---> PCM DAC +-> AMP -> Headphone Jack - * |M| A +--------> Line Out - * |A| <~~clk~~+ - * |P| <--- TWL4030 <--------- Line In and MICs - */ -static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { - SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, - 0, 0, NULL, 0, omap3pandora_hp_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), -}; - -static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Mic (Internal)", NULL), - SND_SOC_DAPM_MIC("Mic (external)", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route omap3pandora_out_map[] = { - {"Headphone Amplifier", NULL, "PCM DAC"}, - {"Line Out", NULL, "PCM DAC"}, - {"Headphone Jack", NULL, "Headphone Amplifier"}, -}; - -static const struct snd_soc_dapm_route omap3pandora_in_map[] = { - {"INL", NULL, "Line In"}, - {"INR", NULL, "Line In"}, - {"INL", NULL, "Mic (Internal)"}, - {"INR", NULL, "Mic (external)"}, -}; - -static int omap3pandora_out_init(struct snd_soc_codec *codec) -{ - int ret; - - ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, - ARRAY_SIZE(omap3pandora_out_dapm_widgets)); - if (ret < 0) - return ret; - - snd_soc_dapm_add_routes(codec, omap3pandora_out_map, - ARRAY_SIZE(omap3pandora_out_map)); - - return snd_soc_dapm_sync(codec); -} - -static int omap3pandora_in_init(struct snd_soc_codec *codec) -{ - int ret; - - ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, - ARRAY_SIZE(omap3pandora_in_dapm_widgets)); - if (ret < 0) - return ret; - - snd_soc_dapm_add_routes(codec, omap3pandora_in_map, - ARRAY_SIZE(omap3pandora_in_map)); - - return snd_soc_dapm_sync(codec); -} - -static struct snd_soc_ops omap3pandora_out_ops = { - .hw_params = omap3pandora_out_hw_params, -}; - -static struct snd_soc_ops omap3pandora_in_ops = { - .hw_params = omap3pandora_in_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3pandora_dai[] = { - { - .name = "PCM1773", - .stream_name = "HiFi Out", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &omap3pandora_out_ops, - .init = omap3pandora_out_init, - }, { - .name = "TWL4030", - .stream_name = "Line/Mic In", - .cpu_dai = &omap_mcbsp_dai[1], - .codec_dai = &twl4030_dai, - .ops = &omap3pandora_in_ops, - .init = omap3pandora_in_init, - } -}; - -/* SoC card */ -static struct snd_soc_card snd_soc_card_omap3pandora = { - .name = "omap3pandora", - .platform = &omap_soc_platform, - .dai_link = omap3pandora_dai, - .num_links = ARRAY_SIZE(omap3pandora_dai), -}; - -/* Audio subsystem */ -static struct snd_soc_device omap3pandora_snd_data = { - .card = &snd_soc_card_omap3pandora, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *omap3pandora_snd_device; - -static int __init omap3pandora_soc_init(void) -{ - int ret; - - if (!machine_is_omap3_pandora()) { - pr_debug(PREFIX "Not OMAP3 Pandora\n"); - return -ENODEV; - } - pr_info("OMAP3 Pandora SoC init\n"); - - ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); - if (ret) { - pr_err(PREFIX "Failed to get DAC power GPIO\n"); - return ret; - } - - ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0); - if (ret) { - pr_err(PREFIX "Failed to set DAC power GPIO direction\n"); - goto fail0; - } - - ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power"); - if (ret) { - pr_err(PREFIX "Failed to get amp power GPIO\n"); - goto fail0; - } - - ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0); - if (ret) { - pr_err(PREFIX "Failed to set amp power GPIO direction\n"); - goto fail1; - } - - omap3pandora_snd_device = platform_device_alloc("soc-audio", -1); - if (omap3pandora_snd_device == NULL) { - pr_err(PREFIX "Platform device allocation failed\n"); - ret = -ENOMEM; - goto fail1; - } - - platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data); - omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev; - *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */ - *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */ - - ret = platform_device_add(omap3pandora_snd_device); - if (ret) { - pr_err(PREFIX "Unable to add platform device\n"); - goto fail2; - } - - return 0; - -fail2: - platform_device_put(omap3pandora_snd_device); -fail1: - gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); -fail0: - gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); - return ret; -} -module_init(omap3pandora_soc_init); - -static void __exit omap3pandora_soc_exit(void) -{ - platform_device_unregister(omap3pandora_snd_device); - gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); - gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); -} -module_exit(omap3pandora_soc_exit); - -MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>"); -MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 845bf41335b9..0fe733796898 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -143,16 +143,16 @@ static struct snd_soc_dai_link osk_dai = { }; /* Audio machine driver */ -static struct snd_soc_card snd_soc_card_osk = { +static struct snd_soc_machine snd_soc_machine_osk = { .name = "OSK5912", - .platform = &omap_soc_platform, .dai_link = &osk_dai, .num_links = 1, }; /* Audio subsystem */ static struct snd_soc_device osk_snd_devdata = { - .card = &snd_soc_card_osk, + .machine = &snd_soc_machine_osk, + .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_tlv320aic23, }; diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c deleted file mode 100644 index a72dc4e159e5..000000000000 --- a/sound/soc/omap/overo.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * overo.c -- SoC audio for Gumstix Overo - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int overo_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops overo_ops = { - .hw_params = overo_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link overo_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &overo_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_card_overo = { - .name = "overo", - .platform = &omap_soc_platform, - .dai_link = &overo_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device overo_snd_devdata = { - .card = &snd_soc_card_overo, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *overo_snd_device; - -static int __init overo_soc_init(void) -{ - int ret; - - if (!machine_is_overo()) { - pr_debug("Not Overo!\n"); - return -ENODEV; - } - printk(KERN_INFO "overo SoC init\n"); - - overo_snd_device = platform_device_alloc("soc-audio", -1); - if (!overo_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(overo_snd_device, &overo_snd_devdata); - overo_snd_devdata.dev = &overo_snd_device->dev; - *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(overo_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(overo_snd_device); - - return ret; -} -module_init(overo_soc_init); - -static void __exit overo_soc_exit(void) -{ - platform_device_unregister(overo_snd_device); -} -module_exit(overo_soc_exit); - -MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); -MODULE_DESCRIPTION("ALSA SoC overo"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c deleted file mode 100644 index ad97836818b1..000000000000 --- a/sound/soc/omap/sdp3430.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * sdp3430.c -- SoC audio for TI OMAP3430 SDP - * - * Author: Misael Lopez Cruz <x0052729@ti.com> - * - * Based on: - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int sdp3430_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops sdp3430_ops = { - .hw_params = sdp3430_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sdp3430_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &sdp3430_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_sdp3430 = { - .name = "SDP3430", - .platform = &omap_soc_platform, - .dai_link = &sdp3430_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device sdp3430_snd_devdata = { - .machine = &snd_soc_machine_sdp3430, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *sdp3430_snd_device; - -static int __init sdp3430_soc_init(void) -{ - int ret; - - if (!machine_is_omap_3430sdp()) { - pr_debug("Not SDP3430!\n"); - return -ENODEV; - } - printk(KERN_INFO "SDP3430 SoC init\n"); - - sdp3430_snd_device = platform_device_alloc("soc-audio", -1); - if (!sdp3430_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata); - sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev; - *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(sdp3430_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(sdp3430_snd_device); - - return ret; -} -module_init(sdp3430_soc_init); - -static void __exit sdp3430_soc_exit(void) -{ - platform_device_unregister(sdp3430_snd_device); -} -module_exit(sdp3430_soc_exit); - -MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>"); -MODULE_DESCRIPTION("ALSA SoC SDP3430"); -MODULE_LICENSE("GPL"); - diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index f82e10699471..f8c1cdd940ac 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -21,9 +21,6 @@ config SND_PXA2XX_SOC_AC97 config SND_PXA2XX_SOC_I2S tristate -config SND_PXA_SOC_SSP - tristate - config SND_PXA2XX_SOC_CORGI tristate "SoC Audio support for Sharp Zaurus SL-C7x0" depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx @@ -78,22 +75,3 @@ config SND_PXA2XX_SOC_EM_X270 help Say Y if you want to add support for SoC audio on CompuLab EM-x270. - -config SND_PXA2XX_SOC_PALM27X - bool "SoC Audio support for Palm T|X, T5 and LifeDrive" - depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || MACH_PALMT5) - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for SoC audio on - Palm T|X, T5 or LifeDrive handheld computer. - -config SND_SOC_ZYLONITE - tristate "SoC Audio support for Marvell Zylonite" - depends on SND_PXA2XX_SOC && MACH_ZYLONITE - select SND_PXA2XX_SOC_AC97 - select SND_PXA_SOC_SSP - select SND_SOC_WM9713 - help - Say Y if you want to add support for SoC audio on the - Marvell Zylonite reference platform. diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 08a9f2797729..5bc8edf9dca9 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -2,12 +2,10 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o -snd-soc-pxa-ssp-objs := pxa-ssp.o obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o -obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o # PXA Machine Support snd-soc-corgi-objs := corgi.o @@ -16,8 +14,6 @@ snd-soc-tosa-objs := tosa.o snd-soc-e800-objs := e800_wm9712.o snd-soc-spitz-objs := spitz.o snd-soc-em-x270-objs := em-x270.o -snd-soc-palm27x-objs := palm27x.o -snd-soc-zylonite-objs := zylonite.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -25,5 +21,3 @@ obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o -obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o -obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 1ba25a559524..2718eaf7895f 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -108,11 +108,15 @@ static int corgi_startup(struct snd_pcm_substream *substream) } /* we need to unmute the HP at shutdown as the mute burns power on corgi */ -static void corgi_shutdown(struct snd_pcm_substream *substream) +static int corgi_shutdown(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + /* set = unmute headphone */ gpio_set_value(CORGI_GPIO_MUTE_L, 1); gpio_set_value(CORGI_GPIO_MUTE_R, 1); + return 0; } static int corgi_hw_params(struct snd_pcm_substream *substream, @@ -310,9 +314,8 @@ static struct snd_soc_dai_link corgi_dai = { }; /* corgi audio machine driver */ -static struct snd_soc_card snd_soc_corgi = { +static struct snd_soc_machine snd_soc_machine_corgi = { .name = "Corgi", - .platform = &pxa2xx_soc_platform, .dai_link = &corgi_dai, .num_links = 1, }; @@ -325,7 +328,8 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .card = &snd_soc_corgi, + .machine = &snd_soc_machine_corgi, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, }; diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 2e3386dfa0f0..6781c5be242f 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -29,7 +29,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_card e800; +static struct snd_soc_machine e800; static struct snd_soc_dai_link e800_dai[] = { { @@ -40,15 +40,15 @@ static struct snd_soc_dai_link e800_dai[] = { }, }; -static struct snd_soc_card e800 = { +static struct snd_soc_machine e800 = { .name = "Toshiba e800", - .platform = &pxa2xx_soc_platform, .dai_link = e800_dai, .num_links = ARRAY_SIZE(e800_dai), }; static struct snd_soc_device e800_snd_devdata = { - .card = &e800, + .machine = &e800, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index fe4a729ea648..e6ff6929ab4b 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -23,6 +23,7 @@ #include <linux/moduleparam.h> #include <linux/device.h> +#include <sound/driver.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> @@ -52,15 +53,15 @@ static struct snd_soc_dai_link em_x270_dai[] = { }, }; -static struct snd_soc_card em_x270 = { +static struct snd_soc_machine em_x270 = { .name = "EM-X270", - .platform = &pxa2xx_soc_platform, .dai_link = em_x270_dai, .num_links = ARRAY_SIZE(em_x270_dai), }; static struct snd_soc_device em_x270_snd_devdata = { - .card = &em_x270, + .machine = &em_x270, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c deleted file mode 100644 index 4a9cf3083af0..000000000000 --- a/sound/soc/pxa/palm27x.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * linux/sound/soc/pxa/palm27x.c - * - * SoC Audio driver for Palm T|X, T5 and LifeDrive - * - * based on tosa.c - * - * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/gpio.h> -#include <linux/interrupt.h> -#include <linux/irq.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/audio.h> -#include <mach/palmasoc.h> - -#include "../codecs/wm9712.h" -#include "pxa2xx-pcm.h" -#include "pxa2xx-ac97.h" - -static int palm27x_jack_func = 1; -static int palm27x_spk_func = 1; -static int palm27x_ep_gpio = -1; - -static void palm27x_ext_control(struct snd_soc_codec *codec) -{ - if (!palm27x_spk_func) - snd_soc_dapm_enable_pin(codec, "Speaker"); - else - snd_soc_dapm_disable_pin(codec, "Speaker"); - - if (!palm27x_jack_func) - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - else - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - - snd_soc_dapm_sync(codec); -} - -static int palm27x_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->socdev->codec; - - /* check the jack status at stream startup */ - palm27x_ext_control(codec); - return 0; -} - -static struct snd_soc_ops palm27x_ops = { - .startup = palm27x_startup, -}; - -static irqreturn_t palm27x_interrupt(int irq, void *v) -{ - palm27x_spk_func = gpio_get_value(palm27x_ep_gpio); - palm27x_jack_func = !palm27x_spk_func; - return IRQ_HANDLED; -} - -static int palm27x_get_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = palm27x_jack_func; - return 0; -} - -static int palm27x_set_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - if (palm27x_jack_func == ucontrol->value.integer.value[0]) - return 0; - - palm27x_jack_func = ucontrol->value.integer.value[0]; - palm27x_ext_control(codec); - return 1; -} - -static int palm27x_get_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = palm27x_spk_func; - return 0; -} - -static int palm27x_set_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - if (palm27x_spk_func == ucontrol->value.integer.value[0]) - return 0; - - palm27x_spk_func = ucontrol->value.integer.value[0]; - palm27x_ext_control(codec); - return 1; -} - -/* PalmTX machine dapm widgets */ -static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -/* PalmTX audio map */ -static const struct snd_soc_dapm_route audio_map[] = { - /* headphone connected to HPOUTL, HPOUTR */ - {"Headphone Jack", NULL, "HPOUTL"}, - {"Headphone Jack", NULL, "HPOUTR"}, - - /* ext speaker connected to ROUT2, LOUT2 */ - {"Speaker", NULL, "LOUT2"}, - {"Speaker", NULL, "ROUT2"}, -}; - -static const char *jack_function[] = {"Headphone", "Off"}; -static const char *spk_function[] = {"On", "Off"}; -static const struct soc_enum palm27x_enum[] = { - SOC_ENUM_SINGLE_EXT(2, jack_function), - SOC_ENUM_SINGLE_EXT(2, spk_function), -}; - -static const struct snd_kcontrol_new palm27x_controls[] = { - SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack, - palm27x_set_jack), - SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk, - palm27x_set_spk), -}; - -static int palm27x_ac97_init(struct snd_soc_codec *codec) -{ - int i, err; - - snd_soc_dapm_nc_pin(codec, "OUT3"); - snd_soc_dapm_nc_pin(codec, "MONOOUT"); - - /* add palm27x specific controls */ - for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&palm27x_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - - /* add palm27x specific widgets */ - snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, - ARRAY_SIZE(palm27x_dapm_widgets)); - - /* set up palm27x specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_sync(codec); - return 0; -} - -static struct snd_soc_dai_link palm27x_dai[] = { -{ - .name = "AC97 HiFi", - .stream_name = "AC97 HiFi", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], - .init = palm27x_ac97_init, - .ops = &palm27x_ops, -}, -{ - .name = "AC97 Aux", - .stream_name = "AC97 Aux", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], - .ops = &palm27x_ops, -}, -}; - -static struct snd_soc_card palm27x_asoc = { - .name = "Palm/PXA27x", - .platform = &pxa2xx_soc_platform, - .dai_link = palm27x_dai, - .num_links = ARRAY_SIZE(palm27x_dai), -}; - -static struct snd_soc_device palm27x_snd_devdata = { - .card = &palm27x_asoc, - .codec_dev = &soc_codec_dev_wm9712, -}; - -static struct platform_device *palm27x_snd_device; - -static int __init palm27x_asoc_init(void) -{ - int ret; - - if (!(machine_is_palmtx() || machine_is_palmt5() || - machine_is_palmld())) - return -ENODEV; - - ret = gpio_request(palm27x_ep_gpio, "Headphone Jack"); - if (ret) - return ret; - ret = gpio_direction_input(palm27x_ep_gpio); - if (ret) - goto err_alloc; - - if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "Headphone jack", NULL)) - goto err_alloc; - - palm27x_snd_device = platform_device_alloc("soc-audio", -1); - if (!palm27x_snd_device) { - ret = -ENOMEM; - goto err_dev; - } - - platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata); - palm27x_snd_devdata.dev = &palm27x_snd_device->dev; - ret = platform_device_add(palm27x_snd_device); - - if (ret != 0) - goto put_device; - - return 0; - -put_device: - platform_device_put(palm27x_snd_device); -err_dev: - free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); -err_alloc: - gpio_free(palm27x_ep_gpio); - - return ret; -} - -static void __exit palm27x_asoc_exit(void) -{ - free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); - gpio_free(palm27x_ep_gpio); - platform_device_unregister(palm27x_snd_device); -} - -void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) -{ - palm27x_ep_gpio = data->jack_gpio; -} - -module_init(palm27x_asoc_init); -module_exit(palm27x_asoc_exit); - -/* Module information */ -MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); -MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 6e9827189fff..4d9930c52789 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -276,9 +276,8 @@ static struct snd_soc_dai_link poodle_dai = { }; /* poodle audio machine driver */ -static struct snd_soc_card snd_soc_poodle = { +static struct snd_soc_machine snd_soc_machine_poodle = { .name = "Poodle", - .platform = &pxa2xx_soc_platform, .dai_link = &poodle_dai, .num_links = 1, }; @@ -291,7 +290,8 @@ static struct wm8731_setup_data poodle_wm8731_setup = { /* poodle audio subsystem */ static struct snd_soc_device poodle_snd_devdata = { - .card = &snd_soc_poodle, + .machine = &snd_soc_machine_poodle, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &poodle_wm8731_setup, }; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c deleted file mode 100644 index 3587f2fae5f1..000000000000 --- a/sound/soc/pxa/pxa-ssp.c +++ /dev/null @@ -1,931 +0,0 @@ -#define DEBUG -/* - * pxa-ssp.c -- ALSA Soc Audio Layer - * - * Copyright 2005,2008 Wolfson Microelectronics PLC. - * Author: Liam Girdwood - * Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * TODO: - * o Test network mode for > 16bit sample size - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/pxa2xx-lib.h> - -#include <mach/hardware.h> -#include <mach/pxa-regs.h> -#include <mach/regs-ssp.h> -#include <mach/audio.h> -#include <mach/ssp.h> - -#include "pxa2xx-pcm.h" -#include "pxa-ssp.h" - -/* - * SSP audio private data - */ -struct ssp_priv { - struct ssp_dev dev; - unsigned int sysclk; - int dai_fmt; -#ifdef CONFIG_PM - struct ssp_state state; -#endif -}; - -#define PXA2xx_SSP1_BASE 0x41000000 -#define PXA27x_SSP2_BASE 0x41700000 -#define PXA27x_SSP3_BASE 0x41900000 -#define PXA3xx_SSP4_BASE 0x41a00000 - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = { - .name = "SSP1 PCM Mono out", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(14), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = { - .name = "SSP1 PCM Mono in", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(13), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = { - .name = "SSP1 PCM Stereo out", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(14), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = { - .name = "SSP1 PCM Stereo in", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(13), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = { - .name = "SSP2 PCM Mono out", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(16), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = { - .name = "SSP2 PCM Mono in", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(15), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = { - .name = "SSP2 PCM Stereo out", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(16), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = { - .name = "SSP2 PCM Stereo in", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(15), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = { - .name = "SSP3 PCM Mono out", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = { - .name = "SSP3 PCM Mono in", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = { - .name = "SSP3 PCM Stereo out", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = { - .name = "SSP3 PCM Stereo in", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = { - .name = "SSP4 PCM Mono out", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = { - .name = "SSP4 PCM Mono in", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = { - .name = "SSP4 PCM Stereo out", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = { - .name = "SSP4 PCM Stereo in", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static void dump_registers(struct ssp_device *ssp) -{ - dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n", - ssp_read_reg(ssp, SSCR0), ssp_read_reg(ssp, SSCR1), - ssp_read_reg(ssp, SSTO)); - - dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n", - ssp_read_reg(ssp, SSPSP), ssp_read_reg(ssp, SSSR), - ssp_read_reg(ssp, SSACD)); -} - -static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { - { - &pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in, - &pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in, - }, - { - &pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in, - &pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in, - }, - { - &pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in, - &pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in, - }, - { - &pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in, - &pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in, - }, -}; - -static int pxa_ssp_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct ssp_priv *priv = cpu_dai->private_data; - int ret = 0; - - if (!cpu_dai->active) { - ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ); - if (ret < 0) - return ret; - ssp_disable(&priv->dev); - } - return ret; -} - -static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct ssp_priv *priv = cpu_dai->private_data; - - if (!cpu_dai->active) { - ssp_disable(&priv->dev); - ssp_exit(&priv->dev); - } -} - -#ifdef CONFIG_PM - -static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) -{ - struct ssp_priv *priv = cpu_dai->private_data; - - if (!cpu_dai->active) - return 0; - - ssp_save_state(&priv->dev, &priv->state); - clk_disable(priv->dev.ssp->clk); - return 0; -} - -static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) -{ - struct ssp_priv *priv = cpu_dai->private_data; - - if (!cpu_dai->active) - return 0; - - clk_enable(priv->dev.ssp->clk); - ssp_restore_state(&priv->dev, &priv->state); - ssp_enable(&priv->dev); - - return 0; -} - -#else -#define pxa_ssp_suspend NULL -#define pxa_ssp_resume NULL -#endif - -/** - * ssp_set_clkdiv - set SSP clock divider - * @div: serial clock rate divider - */ -static void ssp_set_scr(struct ssp_dev *dev, u32 div) -{ - struct ssp_device *ssp = dev->ssp; - u32 sscr0 = ssp_read_reg(dev->ssp, SSCR0) & ~SSCR0_SCR; - - ssp_write_reg(ssp, SSCR0, (sscr0 | SSCR0_SerClkDiv(div))); -} - -/* - * Set the SSP ports SYSCLK. - */ -static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int val; - - u32 sscr0 = ssp_read_reg(ssp, SSCR0) & - ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); - - dev_dbg(&ssp->pdev->dev, - "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", - cpu_dai->id, clk_id, freq); - - switch (clk_id) { - case PXA_SSP_CLK_NET_PLL: - sscr0 |= SSCR0_MOD; - break; - case PXA_SSP_CLK_PLL: - /* Internal PLL is fixed */ - if (cpu_is_pxa25x()) - priv->sysclk = 1843200; - else - priv->sysclk = 13000000; - break; - case PXA_SSP_CLK_EXT: - priv->sysclk = freq; - sscr0 |= SSCR0_ECS; - break; - case PXA_SSP_CLK_NET: - priv->sysclk = freq; - sscr0 |= SSCR0_NCS | SSCR0_MOD; - break; - case PXA_SSP_CLK_AUDIO: - priv->sysclk = 0; - ssp_set_scr(&priv->dev, 1); - sscr0 |= SSCR0_ADC; - break; - default: - return -ENODEV; - } - - /* The SSP clock must be disabled when changing SSP clock mode - * on PXA2xx. On PXA3xx it must be enabled when doing so. */ - if (!cpu_is_pxa3xx()) - clk_disable(priv->dev.ssp->clk); - val = ssp_read_reg(ssp, SSCR0) | sscr0; - ssp_write_reg(ssp, SSCR0, val); - if (!cpu_is_pxa3xx()) - clk_enable(priv->dev.ssp->clk); - - return 0; -} - -/* - * Set the SSP clock dividers. - */ -static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int val; - - switch (div_id) { - case PXA_SSP_AUDIO_DIV_ACDS: - val = (ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div); - ssp_write_reg(ssp, SSACD, val); - break; - case PXA_SSP_AUDIO_DIV_SCDB: - val = ssp_read_reg(ssp, SSACD); - val &= ~SSACD_SCDB; -#if defined(CONFIG_PXA3xx) - if (cpu_is_pxa3xx()) - val &= ~SSACD_SCDX8; -#endif - switch (div) { - case PXA_SSP_CLK_SCDB_1: - val |= SSACD_SCDB; - break; - case PXA_SSP_CLK_SCDB_4: - break; -#if defined(CONFIG_PXA3xx) - case PXA_SSP_CLK_SCDB_8: - if (cpu_is_pxa3xx()) - val |= SSACD_SCDX8; - else - return -EINVAL; - break; -#endif - default: - return -EINVAL; - } - ssp_write_reg(ssp, SSACD, val); - break; - case PXA_SSP_DIV_SCR: - ssp_set_scr(&priv->dev, div); - break; - default: - return -ENODEV; - } - - return 0; -} - -/* - * Configure the PLL frequency pxa27x and (afaik - pxa320 only) - */ -static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70; - -#if defined(CONFIG_PXA3xx) - if (cpu_is_pxa3xx()) - ssp_write_reg(ssp, SSACDD, 0); -#endif - - switch (freq_out) { - case 5622000: - break; - case 11345000: - ssacd |= (0x1 << 4); - break; - case 12235000: - ssacd |= (0x2 << 4); - break; - case 14857000: - ssacd |= (0x3 << 4); - break; - case 32842000: - ssacd |= (0x4 << 4); - break; - case 48000000: - ssacd |= (0x5 << 4); - break; - case 0: - /* Disable */ - break; - - default: -#ifdef CONFIG_PXA3xx - /* PXA3xx has a clock ditherer which can be used to generate - * a wider range of frequencies - calculate a value for it. - */ - if (cpu_is_pxa3xx()) { - u32 val; - u64 tmp = 19968; - tmp *= 1000000; - do_div(tmp, freq_out); - val = tmp; - - val = (val << 16) | 64;; - ssp_write_reg(ssp, SSACDD, val); - - ssacd |= (0x6 << 4); - - dev_dbg(&ssp->pdev->dev, - "Using SSACDD %x to supply %dHz\n", - val, freq_out); - break; - } -#endif - - return -EINVAL; - } - - ssp_write_reg(ssp, SSACD, ssacd); - - return 0; -} - -/* - * Set the active slots in TDM/Network mode - */ -static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, - unsigned int mask, int slots) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 sscr0; - - sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7); - - /* set number of active slots */ - sscr0 |= SSCR0_SlotsPerFrm(slots); - ssp_write_reg(ssp, SSCR0, sscr0); - - /* set active slot mask */ - ssp_write_reg(ssp, SSTSA, mask); - ssp_write_reg(ssp, SSRSA, mask); - return 0; -} - -/* - * Tristate the SSP DAI lines - */ -static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai, - int tristate) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 sscr1; - - sscr1 = ssp_read_reg(ssp, SSCR1); - if (tristate) - sscr1 &= ~SSCR1_TTE; - else - sscr1 |= SSCR1_TTE; - ssp_write_reg(ssp, SSCR1, sscr1); - - return 0; -} - -/* - * Set up the SSP DAI format. - * The SSP Port must be inactive before calling this function as the - * physical interface format is changed. - */ -static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 sscr0; - u32 sscr1; - u32 sspsp; - - /* reset port settings */ - sscr0 = ssp_read_reg(ssp, SSCR0) & - (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); - sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); - sspsp = 0; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR; - break; - case SND_SOC_DAIFMT_CBM_CFS: - sscr1 |= SSCR1_SCLKDIR; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - ssp_write_reg(ssp, SSCR0, sscr0); - ssp_write_reg(ssp, SSCR1, sscr1); - ssp_write_reg(ssp, SSPSP, sspsp); - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - sscr0 |= SSCR0_MOD | SSCR0_PSP; - sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - sspsp |= SSPSP_FSRT; - break; - case SND_SOC_DAIFMT_NB_IF: - sspsp |= SSPSP_SFRMP | SSPSP_FSRT; - break; - case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SFRMP; - break; - default: - return -EINVAL; - } - break; - - case SND_SOC_DAIFMT_DSP_A: - sspsp |= SSPSP_FSRT; - case SND_SOC_DAIFMT_DSP_B: - sscr0 |= SSCR0_MOD | SSCR0_PSP; - sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - sspsp |= SSPSP_SFRMP; - break; - case SND_SOC_DAIFMT_IB_IF: - break; - default: - return -EINVAL; - } - break; - - default: - return -EINVAL; - } - - ssp_write_reg(ssp, SSCR0, sscr0); - ssp_write_reg(ssp, SSCR1, sscr1); - ssp_write_reg(ssp, SSPSP, sspsp); - - dump_registers(ssp); - - /* Since we are configuring the timings for the format by hand - * we have to defer some things until hw_params() where we - * know parameters like the sample size. - */ - priv->dai_fmt = fmt; - - return 0; -} - -/* - * Set the SSP audio DMA parameters and sample size. - * Can be called multiple times by oss emulation. - */ -static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int dma = 0, chn = params_channels(params); - u32 sscr0; - u32 sspsp; - int width = snd_pcm_format_physical_width(params_format(params)); - - /* select correct DMA params */ - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - dma = 1; /* capture DMA offset is 1,3 */ - if (chn == 2) - dma += 2; /* stereo DMA offset is 2, mono is 0 */ - cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma]; - - dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma); - - /* we can only change the settings if the port is not in use */ - if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) - return 0; - - /* clear selected SSP bits */ - sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS); - ssp_write_reg(ssp, SSCR0, sscr0); - - /* bit size */ - sscr0 = ssp_read_reg(ssp, SSCR0); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: -#ifdef CONFIG_PXA3xx - if (cpu_is_pxa3xx()) - sscr0 |= SSCR0_FPCKE; -#endif - sscr0 |= SSCR0_DataSize(16); - if (params_channels(params) > 1) - sscr0 |= SSCR0_EDSS; - break; - case SNDRV_PCM_FORMAT_S24_LE: - sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); - /* we must be in network mode (2 slots) for 24 bit stereo */ - break; - case SNDRV_PCM_FORMAT_S32_LE: - sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); - /* we must be in network mode (2 slots) for 32 bit stereo */ - break; - } - ssp_write_reg(ssp, SSCR0, sscr0); - - switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - /* Cleared when the DAI format is set */ - sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width); - ssp_write_reg(ssp, SSPSP, sspsp); - break; - default: - break; - } - - /* We always use a network mode so we always require TDM slots - * - complain loudly and fail if they've not been set up yet. - */ - if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { - dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); - return -EINVAL; - } - - dump_registers(ssp); - - return 0; -} - -static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret = 0; - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int val; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - ssp_enable(&priv->dev); - break; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - val = ssp_read_reg(ssp, SSSR); - ssp_write_reg(ssp, SSSR, val); - break; - case SNDRV_PCM_TRIGGER_START: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - ssp_enable(&priv->dev); - break; - case SNDRV_PCM_TRIGGER_STOP: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - ssp_disable(&priv->dev); - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - break; - - default: - ret = -EINVAL; - } - - dump_registers(ssp); - - return ret; -} - -static int pxa_ssp_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct ssp_priv *priv; - int ret; - - priv = kzalloc(sizeof(struct ssp_priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->dev.ssp = ssp_request(dai->id, "SoC audio"); - if (priv->dev.ssp == NULL) { - ret = -ENODEV; - goto err_priv; - } - - dai->private_data = priv; - - return 0; - -err_priv: - kfree(priv); - return ret; -} - -static void pxa_ssp_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct ssp_priv *priv = dai->private_data; - ssp_free(priv->dev.ssp); -} - -#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - -#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - -struct snd_soc_dai pxa_ssp_dai[] = { - { - .name = "pxa2xx-ssp1", - .id = 0, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, - { .name = "pxa2xx-ssp2", - .id = 1, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, - { - .name = "pxa2xx-ssp3", - .id = 2, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, - { - .name = "pxa2xx-ssp4", - .id = 3, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, -}; -EXPORT_SYMBOL_GPL(pxa_ssp_dai); - -static int __devinit pxa_ssp_init(void) -{ - return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); -} -module_init(pxa_ssp_init); - -static void __exit pxa_ssp_exit(void) -{ - snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); -} -module_exit(pxa_ssp_exit); - -/* Module information */ -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h deleted file mode 100644 index 91deadd55675..000000000000 --- a/sound/soc/pxa/pxa-ssp.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ASoC PXA SSP port support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _PXA_SSP_H -#define _PXA_SSP_H - -/* pxa DAI SSP IDs */ -#define PXA_DAI_SSP1 0 -#define PXA_DAI_SSP2 1 -#define PXA_DAI_SSP3 2 -#define PXA_DAI_SSP4 3 - -/* SSP clock sources */ -#define PXA_SSP_CLK_PLL 0 -#define PXA_SSP_CLK_EXT 1 -#define PXA_SSP_CLK_NET 2 -#define PXA_SSP_CLK_AUDIO 3 -#define PXA_SSP_CLK_NET_PLL 4 - -/* SSP audio dividers */ -#define PXA_SSP_AUDIO_DIV_ACDS 0 -#define PXA_SSP_AUDIO_DIV_SCDB 1 -#define PXA_SSP_DIV_SCR 2 - -/* SSP ACDS audio dividers values */ -#define PXA_SSP_CLK_AUDIO_DIV_1 0 -#define PXA_SSP_CLK_AUDIO_DIV_2 1 -#define PXA_SSP_CLK_AUDIO_DIV_4 2 -#define PXA_SSP_CLK_AUDIO_DIV_8 3 -#define PXA_SSP_CLK_AUDIO_DIV_16 4 -#define PXA_SSP_CLK_AUDIO_DIV_32 5 - -/* SSP divider bypass */ -#define PXA_SSP_CLK_SCDB_4 0 -#define PXA_SSP_CLK_SCDB_1 1 -#define PXA_SSP_CLK_SCDB_8 2 - -#define PXA_SSP_PLL_OUT 0 - -extern struct snd_soc_dai pxa_ssp_dai[4]; - -#endif diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 2574d323ae51..5e727393cfd4 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -88,12 +88,14 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { }; #ifdef CONFIG_PM -static int pxa2xx_ac97_suspend(struct snd_soc_dai *dai) +static int pxa2xx_ac97_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_suspend(); } -static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) +static int pxa2xx_ac97_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_resume(); } @@ -116,8 +118,7 @@ static void pxa2xx_ac97_remove(struct platform_device *pdev, } static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -131,8 +132,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -146,8 +146,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -172,7 +171,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = pxa2xx_ac97_probe, .remove = pxa2xx_ac97_remove, .suspend = pxa2xx_ac97_suspend, @@ -195,7 +194,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-aux", .id = 1, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .playback = { .stream_name = "AC97 Aux Playback", .channels_min = 1, @@ -214,7 +213,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 2, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, @@ -229,18 +228,6 @@ struct snd_soc_dai pxa_ac97_dai[] = { EXPORT_SYMBOL_GPL(pxa_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit pxa_ac97_init(void) -{ - return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); -} -module_init(pxa_ac97_init); - -static void __exit pxa_ac97_exit(void) -{ - snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); -} -module_exit(pxa_ac97_exit); - MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 517991fb1099..e758034db5c3 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -121,8 +121,7 @@ static struct pxa2xx_gpio gpio_bus[] = { }, }; -static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -188,8 +187,7 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, } static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -250,8 +248,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int ret = 0; @@ -272,8 +269,7 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { SACR1 |= SACR1_DRPL; @@ -293,7 +289,8 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, } #ifdef CONFIG_PM -static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) +static int pxa2xx_i2s_suspend(struct platform_device *dev, + struct snd_soc_dai *dai) { if (!dai->active) return 0; @@ -310,7 +307,8 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) return 0; } -static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) +static int pxa2xx_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { if (!dai->active) return 0; @@ -338,6 +336,7 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) struct snd_soc_dai pxa_i2s_dai = { .name = "pxa2xx-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .suspend = pxa2xx_i2s_suspend, .resume = pxa2xx_i2s_resume, .playback = { @@ -354,7 +353,8 @@ struct snd_soc_dai pxa_i2s_dai = { .startup = pxa2xx_i2s_startup, .shutdown = pxa2xx_i2s_shutdown, .trigger = pxa2xx_i2s_trigger, - .hw_params = pxa2xx_i2s_hw_params, + .hw_params = pxa2xx_i2s_hw_params,}, + .dai_ops = { .set_fmt = pxa2xx_i2s_set_dai_fmt, .set_sysclk = pxa2xx_i2s_set_dai_sysclk, }, @@ -364,23 +364,12 @@ EXPORT_SYMBOL_GPL(pxa_i2s_dai); static int pxa2xx_i2s_probe(struct platform_device *dev) { - int ret; - clk_i2s = clk_get(&dev->dev, "I2SCLK"); - if (IS_ERR(clk_i2s)) - return PTR_ERR(clk_i2s); - - pxa_i2s_dai.dev = &dev->dev; - ret = snd_soc_register_dai(&pxa_i2s_dai); - if (ret != 0) - clk_put(clk_i2s); - - return ret; + return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0; } static int __devexit pxa2xx_i2s_remove(struct platform_device *dev) { - snd_soc_unregister_dai(&pxa_i2s_dai); clk_put(clk_i2s); clk_i2s = ERR_PTR(-ENOENT); return 0; diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 4fa1578f5d47..afcd892cd2fa 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -69,7 +69,7 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops pxa2xx_pcm_ops = { +struct snd_pcm_ops pxa2xx_pcm_ops = { .open = __pxa2xx_pcm_open, .close = __pxa2xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, @@ -118,18 +118,6 @@ struct snd_soc_platform pxa2xx_soc_platform = { }; EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); -static int __devinit pxa2xx_soc_platform_init(void) -{ - return snd_soc_register_platform(&pxa2xx_soc_platform); -} -module_init(pxa2xx_soc_platform_init); - -static void __exit pxa2xx_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&pxa2xx_soc_platform); -} -module_exit(pxa2xx_soc_platform_exit); - MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index a3b9e6bdf979..d307b6757e95 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -319,9 +319,8 @@ static struct snd_soc_dai_link spitz_dai = { }; /* spitz audio machine driver */ -static struct snd_soc_card snd_soc_spitz = { +static struct snd_soc_machine snd_soc_machine_spitz = { .name = "Spitz", - .platform = &pxa2xx_soc_platform, .dai_link = &spitz_dai, .num_links = 1, }; @@ -334,7 +333,8 @@ static struct wm8750_setup_data spitz_wm8750_setup = { /* spitz audio subsystem */ static struct snd_soc_device spitz_snd_devdata = { - .card = &snd_soc_spitz, + .machine = &snd_soc_machine_spitz, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8750, .codec_data = &spitz_wm8750_setup, }; diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index c77194f74c9b..afefe41b8c46 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -38,7 +38,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_card tosa; +static struct snd_soc_machine tosa; #define TOSA_HP 0 #define TOSA_MIC_INT 1 @@ -230,37 +230,15 @@ static struct snd_soc_dai_link tosa_dai[] = { }, }; -static int tosa_probe(struct platform_device *dev) -{ - int ret; - - ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); - if (ret) - return ret; - ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0); - if (ret) - gpio_free(TOSA_GPIO_L_MUTE); - - return ret; -} - -static int tosa_remove(struct platform_device *dev) -{ - gpio_free(TOSA_GPIO_L_MUTE); - return 0; -} - -static struct snd_soc_card tosa = { +static struct snd_soc_machine tosa = { .name = "Tosa", - .platform = &pxa2xx_soc_platform, .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), - .probe = tosa_probe, - .remove = tosa_remove, }; static struct snd_soc_device tosa_snd_devdata = { - .card = &tosa, + .machine = &tosa, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; @@ -273,6 +251,11 @@ static int __init tosa_init(void) if (!machine_is_tosa()) return -ENODEV; + ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); + if (ret) + return ret; + gpio_direction_output(TOSA_GPIO_L_MUTE, 0); + tosa_snd_device = platform_device_alloc("soc-audio", -1); if (!tosa_snd_device) { ret = -ENOMEM; @@ -289,12 +272,15 @@ static int __init tosa_init(void) platform_device_put(tosa_snd_device); err_alloc: + gpio_free(TOSA_GPIO_L_MUTE); + return ret; } static void __exit tosa_exit(void) { platform_device_unregister(tosa_snd_device); + gpio_free(TOSA_GPIO_L_MUTE); } module_init(tosa_init); diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c deleted file mode 100644 index f8e9ecd589d3..000000000000 --- a/sound/soc/pxa/zylonite.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * zylonite.c -- SoC audio for Zylonite - * - * Copyright 2008 Wolfson Microelectronics PLC. - * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/i2c.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include "../codecs/wm9713.h" -#include "pxa2xx-pcm.h" -#include "pxa2xx-ac97.h" -#include "pxa-ssp.h" - -static struct snd_soc_card zylonite; - -static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Microphone", NULL), - SND_SOC_DAPM_MIC("Handset Microphone", NULL), - SND_SOC_DAPM_SPK("Multiactor", NULL), - SND_SOC_DAPM_SPK("Headset Earpiece", NULL), -}; - -/* Currently supported audio map */ -static const struct snd_soc_dapm_route audio_map[] = { - - /* Headphone output connected to HPL/HPR */ - { "Headphone", NULL, "HPL" }, - { "Headphone", NULL, "HPR" }, - - /* On-board earpiece */ - { "Headset Earpiece", NULL, "OUT3" }, - - /* Headphone mic */ - { "MIC2A", NULL, "Mic Bias" }, - { "Mic Bias", NULL, "Headset Microphone" }, - - /* On-board mic */ - { "MIC1", NULL, "Mic Bias" }, - { "Mic Bias", NULL, "Handset Microphone" }, - - /* Multiactor differentially connected over SPKL/SPKR */ - { "Multiactor", NULL, "SPKL" }, - { "Multiactor", NULL, "SPKR" }, -}; - -static int zylonite_wm9713_init(struct snd_soc_codec *codec) -{ - /* Currently we only support use of the AC97 clock here. If - * CLK_POUT is selected by SW15 then the clock API will need - * to be used to request and enable it here. - */ - - snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, - ARRAY_SIZE(zylonite_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - /* Static setup for now */ - snd_soc_dapm_enable_pin(codec, "Headphone"); - snd_soc_dapm_enable_pin(codec, "Headset Earpiece"); - - snd_soc_dapm_sync(codec); - return 0; -} - -static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int pll_out = 0; - unsigned int acds = 0; - unsigned int wm9713_div = 0; - int ret = 0; - - switch (params_rate(params)) { - case 8000: - wm9713_div = 12; - pll_out = 2048000; - break; - case 16000: - wm9713_div = 6; - pll_out = 4096000; - break; - case 48000: - default: - wm9713_div = 2; - pll_out = 12288000; - acds = 1; - break; - } - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_tdm_slot(cpu_dai, - params_channels(params), - params_channels(params)); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); - if (ret < 0) - return ret; - - /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs - * to be set instead. - */ - ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, - WM9713_PCMDIV(wm9713_div)); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops zylonite_voice_ops = { - .hw_params = zylonite_voice_hw_params, -}; - -static struct snd_soc_dai_link zylonite_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], - .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], - .init = zylonite_wm9713_init, -}, -{ - .name = "AC97 Aux", - .stream_name = "AC97 Aux", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], - .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX], -}, -{ - .name = "WM9713 Voice", - .stream_name = "WM9713 Voice", - .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3], - .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE], - .ops = &zylonite_voice_ops, -}, -}; - -static struct snd_soc_card zylonite = { - .name = "Zylonite", - .platform = &pxa2xx_soc_platform, - .dai_link = zylonite_dai, - .num_links = ARRAY_SIZE(zylonite_dai), -}; - -static struct snd_soc_device zylonite_snd_ac97_devdata = { - .card = &zylonite, - .codec_dev = &soc_codec_dev_wm9713, -}; - -static struct platform_device *zylonite_snd_ac97_device; - -static int __init zylonite_init(void) -{ - int ret; - - zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!zylonite_snd_ac97_device) - return -ENOMEM; - - platform_set_drvdata(zylonite_snd_ac97_device, - &zylonite_snd_ac97_devdata); - zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev; - - ret = platform_device_add(zylonite_snd_ac97_device); - if (ret != 0) - platform_device_put(zylonite_snd_ac97_device); - - return ret; -} - -static void __exit zylonite_exit(void) -{ - platform_device_unregister(zylonite_snd_ac97_device); -} - -module_init(zylonite_init); -module_exit(zylonite_exit); - -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index fcd03acf10f6..b9f2353effeb 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -44,8 +44,3 @@ config SND_S3C24XX_SOC_LN2440SBC_ALC650 Say Y if you want to add support for SoC audio on ln2440sbc with the ALC650. -config SND_S3C24XX_SOC_S3C24XX_UDA134X - tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" - depends on SND_S3C24XX_SOC - select SND_S3C24XX_SOC_I2S - select SND_SOC_UDA134X diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 96b3f3f617d4..0aa5fb0b9700 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -13,9 +13,7 @@ obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o -snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o -obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index 12c71482d258..4eab2c19c454 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -27,7 +27,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_card ln2440sbc; +static struct snd_soc_machine ln2440sbc; static struct snd_soc_dai_link ln2440sbc_dai[] = { { @@ -38,15 +38,15 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { }, }; -static struct snd_soc_card ln2440sbc = { +static struct snd_soc_machine ln2440sbc = { .name = "LN2440SBC", - .platform = &s3c24xx_soc_platform, .dai_link = ln2440sbc_dai, .num_links = ARRAY_SIZE(ln2440sbc_dai), }; static struct snd_soc_device ln2440sbc_snd_ac97_devdata = { - .card = &ln2440sbc, + .machine = &ln2440sbc, + .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 45bb12e8ea44..87ddfefcc2fb 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -59,7 +59,7 @@ #define NEO_CAPTURE_HEADSET 7 #define NEO_CAPTURE_BLUETOOTH 8 -static struct snd_soc_card neo1973; +static struct snd_soc_machine neo1973; static struct i2c_client *i2c; static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, @@ -548,6 +548,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) static struct snd_soc_dai bt_dai = { .name = "Bluetooth", .id = 0, + .type = SND_SOC_DAI_PCM, .playback = { .channels_min = 1, .channels_max = 1, @@ -578,9 +579,8 @@ static struct snd_soc_dai_link neo1973_dai[] = { }, }; -static struct snd_soc_card neo1973 = { +static struct snd_soc_machine neo1973 = { .name = "neo1973", - .platform = &s3c24xx_soc_platform, .dai_link = neo1973_dai, .num_links = ARRAY_SIZE(neo1973_dai), }; @@ -591,7 +591,8 @@ static struct wm8753_setup_data neo1973_wm8753_setup = { }; static struct snd_soc_device neo1973_snd_devdata = { - .card = &neo1973, + .machine = &neo1973, + .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_wm8753, .codec_data = &neo1973_wm8753_setup, }; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 2cf050791562..ded7d995a922 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -343,8 +343,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -374,8 +373,7 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; @@ -649,7 +647,8 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) +static int s3c2412_i2s_suspend(struct platform_device *dev, + struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; u32 iismod; @@ -664,24 +663,25 @@ static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) iismod = readl(i2s->regs + S3C2412_IISMOD); if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) - pr_warning("%s: RXDMA active?\n", __func__); + dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) - pr_warning("%s: TXDMA active?\n", __func__); + dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_IIS_ACTIVE) - pr_warning("%s: IIS active\n", __func__); + dev_warn(&dev->dev, "%s: IIS active\n", __func__); } return 0; } -static int s3c2412_i2s_resume(struct snd_soc_dai *dai) +static int s3c2412_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; - pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", - dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); + dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n", + dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); if (dai->active) { writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); @@ -711,6 +711,7 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) struct snd_soc_dai s3c2412_i2s_dai = { .name = "s3c2412-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = s3c2412_i2s_probe, .suspend = s3c2412_i2s_suspend, .resume = s3c2412_i2s_resume, @@ -729,6 +730,8 @@ struct snd_soc_dai s3c2412_i2s_dai = { .ops = { .trigger = s3c2412_i2s_trigger, .hw_params = s3c2412_i2s_hw_params, + }, + .dai_ops = { .set_fmt = s3c2412_i2s_set_fmt, .set_clkdiv = s3c2412_i2s_set_clkdiv, .set_sysclk = s3c2412_i2s_set_sysclk, @@ -736,19 +739,6 @@ struct snd_soc_dai s3c2412_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); -static int __devinit s3c2412_i2s_init(void) -{ - return snd_soc_register_dai(&s3c2412_i2s_dai); -} -module_init(s3c2412_i2s_init); - -static void __exit s3c2412_i2s_exit(void) -{ - snd_soc_unregister_dai(&s3c2412_i2s_dai); -} -module_exit(s3c2412_i2s_exit); - - /* Module information */ MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index aa99e1615eff..c473a3b97b55 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -271,8 +271,7 @@ static void s3c2443_ac97_remove(struct platform_device *pdev, } static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -285,8 +284,7 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd) { u32 ac_glbctrl; @@ -315,8 +313,7 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, } static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -330,7 +327,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, } static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) + int cmd) { u32 ac_glbctrl; @@ -359,7 +356,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "s3c2443-ac97", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = s3c2443_ac97_probe, .remove = s3c2443_ac97_remove, .playback = { @@ -381,7 +378,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 1, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, @@ -396,19 +393,6 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit s3c2443_ac97_init(void) -{ - return snd_soc_register_dai(&s3c2443_ac97_dai); -} -module_init(s3c2443_ac97_init); - -static void __exit s3c2443_ac97_exit(void) -{ - snd_soc_unregister_dai(&s3c2443_ac97_dai); -} -module_exit(s3c2443_ac97_exit); - - MODULE_AUTHOR("Graeme Gregory"); MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 897b1ac92cef..ba4476b55fbc 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -243,8 +243,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -262,17 +261,10 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - iismod &= ~S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size = 1; break; case SNDRV_PCM_FORMAT_S16_LE: iismod |= S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size = 2; break; - default: - return -EINVAL; } writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -280,8 +272,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int ret = 0; @@ -419,7 +410,8 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); @@ -433,7 +425,8 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) return 0; } -static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); clk_enable(s3c24xx_i2s.iis_clk); @@ -459,6 +452,7 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) struct snd_soc_dai s3c24xx_i2s_dai = { .name = "s3c24xx-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = s3c24xx_i2s_probe, .suspend = s3c24xx_i2s_suspend, .resume = s3c24xx_i2s_resume, @@ -474,7 +468,8 @@ struct snd_soc_dai s3c24xx_i2s_dai = { .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .trigger = s3c24xx_i2s_trigger, - .hw_params = s3c24xx_i2s_hw_params, + .hw_params = s3c24xx_i2s_hw_params,}, + .dai_ops = { .set_fmt = s3c24xx_i2s_set_fmt, .set_clkdiv = s3c24xx_i2s_set_clkdiv, .set_sysclk = s3c24xx_i2s_set_sysclk, @@ -482,18 +477,6 @@ struct snd_soc_dai s3c24xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); -static int __devinit s3c24xx_i2s_init(void) -{ - return snd_soc_register_dai(&s3c24xx_i2s_dai); -} -module_init(s3c24xx_i2s_init); - -static void __exit s3c24xx_i2s_exit(void) -{ - snd_soc_unregister_dai(&s3c24xx_i2s_dai); -} -module_exit(s3c24xx_i2s_exit); - /* Module information */ MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("s3c24xx I2S SoC Interface"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index ea5a9caec13e..e13e614bada9 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -465,18 +465,6 @@ struct snd_soc_platform s3c24xx_soc_platform = { }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); -static int __devinit s3c24xx_soc_platform_init(void) -{ - return snd_soc_register_platform(&s3c24xx_soc_platform); -} -module_init(s3c24xx_soc_platform_init); - -static void __exit s3c24xx_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&s3c24xx_soc_platform); -} -module_exit(s3c24xx_soc_platform_exit); - MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c deleted file mode 100644 index a0a4d1832a14..000000000000 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Modifications by Christian Pellegrin <chripell@evolware.org> - * - * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/clk.h> -#include <linux/mutex.h> -#include <linux/gpio.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/s3c24xx_uda134x.h> -#include <sound/uda134x.h> - -#include <asm/plat-s3c24xx/regs-iis.h> - -#include "s3c24xx-pcm.h" -#include "s3c24xx-i2s.h" -#include "../codecs/uda134x.h" - - -/* #define ENFORCE_RATES 1 */ -/* - Unfortunately the S3C24XX in master mode has a limited capacity of - generating the clock for the codec. If you define this only rates - that are really available will be enforced. But be careful, most - user level application just want the usual sampling frequencies (8, - 11.025, 22.050, 44.1 kHz) and anyway resampling is a costly - operation for embedded systems. So if you aren't very lucky or your - hardware engineer wasn't very forward-looking it's better to leave - this undefined. If you do so an approximate value for the requested - sampling rate in the range -/+ 5% will be chosen. If this in not - possible an error will be returned. -*/ - -static struct clk *xtal; -static struct clk *pclk; -/* this is need because we don't have a place where to keep the - * pointers to the clocks in each substream. We get the clocks only - * when we are actually using them so we don't block stuff like - * frequency change or oscillator power-off */ -static int clk_users; -static DEFINE_MUTEX(clk_lock); - -static unsigned int rates[33 * 2]; -#ifdef ENFORCE_RATES -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; -#endif - -static struct platform_device *s3c24xx_uda134x_snd_device; - -static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) -{ - int ret = 0; -#ifdef ENFORCE_RATES - struct snd_pcm_runtime *runtime = substream->runtime;; -#endif - - mutex_lock(&clk_lock); - pr_debug("%s %d\n", __func__, clk_users); - if (clk_users == 0) { - xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal"); - if (!xtal) { - printk(KERN_ERR "%s cannot get xtal\n", __func__); - ret = -EBUSY; - } else { - pclk = clk_get(&s3c24xx_uda134x_snd_device->dev, - "pclk"); - if (!pclk) { - printk(KERN_ERR "%s cannot get pclk\n", - __func__); - clk_put(xtal); - ret = -EBUSY; - } - } - if (!ret) { - int i, j; - - for (i = 0; i < 2; i++) { - int fs = i ? 256 : 384; - - rates[i*33] = clk_get_rate(xtal) / fs; - for (j = 1; j < 33; j++) - rates[i*33 + j] = clk_get_rate(pclk) / - (j * fs); - } - } - } - clk_users += 1; - mutex_unlock(&clk_lock); - if (!ret) { -#ifdef ENFORCE_RATES - ret = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &hw_constraints_rates); - if (ret < 0) - printk(KERN_ERR "%s cannot set constraints\n", - __func__); -#endif - } - return ret; -} - -static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) -{ - mutex_lock(&clk_lock); - pr_debug("%s %d\n", __func__, clk_users); - clk_users -= 1; - if (clk_users == 0) { - clk_put(xtal); - xtal = NULL; - clk_put(pclk); - pclk = NULL; - } - mutex_unlock(&clk_lock); -} - -static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int clk = 0; - int ret = 0; - int clk_source, fs_mode; - unsigned long rate = params_rate(params); - long err, cerr; - unsigned int div; - int i, bi; - - err = 999999; - bi = 0; - for (i = 0; i < 2*33; i++) { - cerr = rates[i] - rate; - if (cerr < 0) - cerr = -cerr; - if (cerr < err) { - err = cerr; - bi = i; - } - } - if (bi / 33 == 1) - fs_mode = S3C2410_IISMOD_256FS; - else - fs_mode = S3C2410_IISMOD_384FS; - if (bi % 33 == 0) { - clk_source = S3C24XX_CLKSRC_MPLL; - div = 1; - } else { - clk_source = S3C24XX_CLKSRC_PCLK; - div = bi % 33; - } - pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi); - - clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate; - pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__, - fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS", - clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK", - div, clk, err); - - if ((err * 100 / rate) > 5) { - printk(KERN_ERR "S3C24XX_UDA134X: effective frequency " - "too different from desired (%ld%%)\n", - err * 100 / rate); - return -EINVAL; - } - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk, - SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, - S3C2410_IISMOD_32FS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, - S3C24XX_PRESCALE(div, div)); - if (ret < 0) - return ret; - - /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, - SND_SOC_CLOCK_OUT); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops s3c24xx_uda134x_ops = { - .startup = s3c24xx_uda134x_startup, - .shutdown = s3c24xx_uda134x_shutdown, - .hw_params = s3c24xx_uda134x_hw_params, -}; - -static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { - .name = "UDA134X", - .stream_name = "UDA134X", - .codec_dai = &uda134x_dai, - .cpu_dai = &s3c24xx_i2s_dai, - .ops = &s3c24xx_uda134x_ops, -}; - -static struct snd_soc_card snd_soc_s3c24xx_uda134x = { - .name = "S3C24XX_UDA134X", - .platform = &s3c24xx_soc_platform, - .dai_link = &s3c24xx_uda134x_dai_link, - .num_links = 1, -}; - -static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins; - -static void setdat(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0); -} - -static void setclk(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0); -} - -static void setmode(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0); -} - -static struct uda134x_platform_data s3c24xx_uda134x = { - .l3 = { - .setdat = setdat, - .setclk = setclk, - .setmode = setmode, - .data_hold = 1, - .data_setup = 1, - .clock_high = 1, - .mode_hold = 1, - .mode = 1, - .mode_setup = 1, - }, -}; - -static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { - .card = &snd_soc_s3c24xx_uda134x, - .codec_dev = &soc_codec_dev_uda134x, - .codec_data = &s3c24xx_uda134x, -}; - -static int s3c24xx_uda134x_setup_pin(int pin, char *fun) -{ - if (gpio_request(pin, "s3c24xx_uda134x") < 0) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "l3 %s pin already in use", fun); - return -EBUSY; - } - gpio_direction_output(pin, 0); - return 0; -} - -static int s3c24xx_uda134x_probe(struct platform_device *pdev) -{ - int ret; - - printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n"); - - s3c24xx_uda134x_l3_pins = pdev->dev.platform_data; - if (s3c24xx_uda134x_l3_pins == NULL) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "unable to find platform data\n"); - return -ENODEV; - } - s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power; - s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model; - - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, - "data") < 0) - return -EBUSY; - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, - "clk") < 0) { - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - return -EBUSY; - } - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, - "mode") < 0) { - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); - return -EBUSY; - } - - s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1); - if (!s3c24xx_uda134x_snd_device) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "Unable to register\n"); - return -ENOMEM; - } - - platform_set_drvdata(s3c24xx_uda134x_snd_device, - &s3c24xx_uda134x_snd_devdata); - s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev; - ret = platform_device_add(s3c24xx_uda134x_snd_device); - if (ret) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n"); - platform_device_put(s3c24xx_uda134x_snd_device); - } - - return ret; -} - -static int s3c24xx_uda134x_remove(struct platform_device *pdev) -{ - platform_device_unregister(s3c24xx_uda134x_snd_device); - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); - gpio_free(s3c24xx_uda134x_l3_pins->l3_mode); - return 0; -} - -static struct platform_driver s3c24xx_uda134x_driver = { - .probe = s3c24xx_uda134x_probe, - .remove = s3c24xx_uda134x_remove, - .driver = { - .name = "s3c24xx_uda134x", - .owner = THIS_MODULE, - }, -}; - -static int __init s3c24xx_uda134x_init(void) -{ - return platform_driver_register(&s3c24xx_uda134x_driver); -} - -static void __exit s3c24xx_uda134x_exit(void) -{ - platform_driver_unregister(&s3c24xx_uda134x_driver); -} - - -module_init(s3c24xx_uda134x_init); -module_exit(s3c24xx_uda134x_exit); - -MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>"); -MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index a2a4f5323c17..8515d6ff03f2 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -23,7 +23,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_card smdk2443; +static struct snd_soc_machine smdk2443; static struct snd_soc_dai_link smdk2443_dai[] = { { @@ -34,15 +34,15 @@ static struct snd_soc_dai_link smdk2443_dai[] = { }, }; -static struct snd_soc_card smdk2443 = { +static struct snd_soc_machine smdk2443 = { .name = "SMDK2443", - .platform = &s3c24xx_soc_platform, .dai_link = smdk2443_dai, .num_links = ARRAY_SIZE(smdk2443_dai), }; static struct snd_soc_device smdk2443_snd_ac97_devdata = { - .card = &smdk2443, + .machine = &smdk2443, + .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 39ffca0933a2..9faa12622d09 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -348,18 +348,6 @@ struct snd_soc_platform sh7760_soc_platform = { }; EXPORT_SYMBOL_GPL(sh7760_soc_platform); -static int __devinit sh7760_soc_platform_init(void) -{ - return snd_soc_register_platform(&sh7760_soc_platform); -} -module_init(sh7760_soc_platform_init); - -static void __exit sh7760_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&sh7760_soc_platform); -} -module_exit(sh7760_soc_platform_exit); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver"); MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 9169bad1acfb..df7bc345c320 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -236,8 +236,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int hac_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id]; @@ -271,7 +270,7 @@ struct snd_soc_dai sh4_hac_dai[] = { { .name = "HAC0", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, @@ -291,8 +290,8 @@ struct snd_soc_dai sh4_hac_dai[] = { #ifdef CONFIG_CPU_SUBTYPE_SH7760 { .name = "HAC1", - .ac97_control = 1, .id = 1, + .type = SND_SOC_DAI_AC97, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, @@ -314,18 +313,6 @@ struct snd_soc_dai sh4_hac_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_hac_dai); -static int __devinit sh4_hac_init(void) -{ - return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); -} -module_init(sh4_hac_init); - -static void __exit sh4_hac_exit(void) -{ - snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); -} -module_exit(sh4_hac_exit); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver"); MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index ce7f95b59de3..92bfaf4774a7 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c @@ -38,15 +38,15 @@ static struct snd_soc_dai_link sh7760_ac97_dai = { .ops = NULL, }; -static struct snd_soc_card sh7760_ac97_soc_machine = { +static struct snd_soc_machine sh7760_ac97_soc_machine = { .name = "SH7760 AC97", - .platform = &sh7760_soc_platform, .dai_link = &sh7760_ac97_dai, .num_links = 1, }; static struct snd_soc_device sh7760_ac97_snd_devdata = { - .card = &sh7760_ac97_soc_machine, + .machine = &sh7760_ac97_soc_machine, + .platform = &sh7760_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 9093588d4d07..55c3464163ab 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -89,8 +89,7 @@ struct ssi_priv { * track usage of the SSI; it is simplex-only so prevent attempts of * concurrent playback + capture. FIXME: any locking required? */ -static int ssi_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ssi_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -102,8 +101,7 @@ static int ssi_startup(struct snd_pcm_substream *substream, return 0; } -static void ssi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void ssi_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -111,8 +109,7 @@ static void ssi_shutdown(struct snd_pcm_substream *substream, ssi->inuse = 0; } -static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int ssi_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -132,8 +129,7 @@ static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, } static int ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -340,6 +336,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI0", .id = 0, + .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, @@ -357,6 +354,8 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, + }, + .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, @@ -366,6 +365,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI1", .id = 1, + .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, @@ -383,6 +383,8 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, + }, + .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, @@ -392,18 +394,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_ssi_dai); -static int __devinit sh4_ssi_init(void) -{ - return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); -} -module_init(sh4_ssi_init); - -static void __exit sh4_ssi_exit(void) -{ - snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); -} -module_exit(sh4_ssi_exit); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver"); MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 76a89eb65baf..16c7453f4946 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -26,7 +26,6 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/bitops.h> -#include <linux/debugfs.h> #include <linux/platform_device.h> #include <sound/core.h> #include <sound/pcm.h> @@ -35,22 +34,18 @@ #include <sound/soc-dapm.h> #include <sound/initval.h> +/* debug */ +#define SOC_DEBUG 0 +#if SOC_DEBUG +#define dbg(format, arg...) printk(format, ## arg) +#else +#define dbg(format, arg...) +#endif + static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); -#ifdef CONFIG_DEBUG_FS -static struct dentry *debugfs_root; -#endif - -static DEFINE_MUTEX(client_mutex); -static LIST_HEAD(card_list); -static LIST_HEAD(dai_list); -static LIST_HEAD(platform_list); - -static int snd_soc_register_card(struct snd_soc_card *card); -static int snd_soc_unregister_card(struct snd_soc_card *card); - /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -112,6 +107,20 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) } #endif +static inline const char *get_dai_name(int type) +{ + switch (type) { + case SND_SOC_DAI_AC97_BUS: + case SND_SOC_DAI_AC97: + return "AC97"; + case SND_SOC_DAI_I2S: + return "I2S"; + case SND_SOC_DAI_PCM: + return "PCM"; + } + return NULL; +} + /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -121,10 +130,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card = socdev->card; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -133,7 +141,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* startup the audio subsystem */ if (cpu_dai->ops.startup) { - ret = cpu_dai->ops.startup(substream, cpu_dai); + ret = cpu_dai->ops.startup(substream); if (ret < 0) { printk(KERN_ERR "asoc: can't open interface %s\n", cpu_dai->name); @@ -150,7 +158,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } if (codec_dai->ops.startup) { - ret = codec_dai->ops.startup(substream, codec_dai); + ret = codec_dai->ops.startup(substream); if (ret < 0) { printk(KERN_ERR "asoc: can't open codec %s\n", codec_dai->name); @@ -220,12 +228,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto machine_err; } - pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); - pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); - pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, - runtime->hw.channels_max); - pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, - runtime->hw.rate_max); + dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); + dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); + dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, + runtime->hw.channels_max); + dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, + runtime->hw.rate_max); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cpu_dai->playback.active = codec_dai->playback.active = 1; @@ -247,7 +255,7 @@ codec_dai_err: platform_err: if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream, cpu_dai); + cpu_dai->ops.shutdown(substream); out: mutex_unlock(&pcm_mutex); return ret; @@ -260,9 +268,8 @@ out: */ static void close_delayed_work(struct work_struct *work) { - struct snd_soc_card *card = container_of(work, struct snd_soc_card, - delayed_work.work); - struct snd_soc_device *socdev = card->socdev; + struct snd_soc_device *socdev = + container_of(work, struct snd_soc_device, delayed_work.work); struct snd_soc_codec *codec = socdev->codec; struct snd_soc_dai *codec_dai; int i; @@ -271,18 +278,18 @@ static void close_delayed_work(struct work_struct *work) for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - pr_debug("pop wq checking: %s status: %s waiting: %s\n", - codec_dai->playback.stream_name, - codec_dai->playback.active ? "active" : "inactive", - codec_dai->pop_wait ? "yes" : "no"); + dbg("pop wq checking: %s status: %s waiting: %s\n", + codec_dai->playback.stream_name, + codec_dai->playback.active ? "active" : "inactive", + codec_dai->pop_wait ? "yes" : "no"); /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { /* Reduce power if no longer active */ if (codec->active == 0) { - pr_debug("pop wq D1 %s %s\n", codec->name, - codec_dai->playback.stream_name); + dbg("pop wq D1 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); } @@ -294,8 +301,8 @@ static void close_delayed_work(struct work_struct *work) /* Fall into standby if no longer active */ if (codec->active == 0) { - pr_debug("pop wq D3 %s %s\n", codec->name, - codec_dai->playback.stream_name); + dbg("pop wq D3 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); } @@ -313,9 +320,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -340,10 +346,10 @@ static int soc_codec_close(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(codec_dai, 1); if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream, cpu_dai); + cpu_dai->ops.shutdown(substream); if (codec_dai->ops.shutdown) - codec_dai->ops.shutdown(substream, codec_dai); + codec_dai->ops.shutdown(substream); if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); @@ -355,7 +361,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; - schedule_delayed_work(&card->delayed_work, + schedule_delayed_work(&socdev->delayed_work, msecs_to_jiffies(pmdown_time)); } else { /* capture streams can be powered down now */ @@ -381,9 +387,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -408,7 +413,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (codec_dai->ops.prepare) { - ret = codec_dai->ops.prepare(substream, codec_dai); + ret = codec_dai->ops.prepare(substream); if (ret < 0) { printk(KERN_ERR "asoc: codec DAI prepare error\n"); goto out; @@ -416,49 +421,58 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (cpu_dai->ops.prepare) { - ret = cpu_dai->ops.prepare(substream, cpu_dai); + ret = cpu_dai->ops.prepare(substream); if (ret < 0) { printk(KERN_ERR "asoc: cpu DAI prepare error\n"); goto out; } } - /* cancel any delayed stream shutdown that is pending */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - codec_dai->pop_wait) { - codec_dai->pop_wait = 0; - cancel_delayed_work(&card->delayed_work); - } + /* we only want to start a DAPM playback stream if we are not waiting + * on an existing one stopping */ + if (codec_dai->pop_wait) { + /* we are waiting for the delayed work to start */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + snd_soc_dapm_stream_event(socdev->codec, + codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); + else { + codec_dai->pop_wait = 0; + cancel_delayed_work(&socdev->delayed_work); + snd_soc_dai_digital_mute(codec_dai, 0); + } + } else { + /* no delayed work - do we need to power up codec */ + if (codec->bias_level != SND_SOC_BIAS_ON) { - /* do we need to power up codec */ - if (codec->bias_level != SND_SOC_BIAS_ON) { - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_PREPARE); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); - snd_soc_dai_digital_mute(codec_dai, 0); + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); + snd_soc_dai_digital_mute(codec_dai, 0); - } else { - /* codec already powered - power on widgets */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, + } else { + /* codec already powered - power on widgets */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dai_digital_mute(codec_dai, 0); + snd_soc_dai_digital_mute(codec_dai, 0); + } } out: @@ -477,8 +491,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -494,7 +507,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (codec_dai->ops.hw_params) { - ret = codec_dai->ops.hw_params(substream, params, codec_dai); + ret = codec_dai->ops.hw_params(substream, params); if (ret < 0) { printk(KERN_ERR "asoc: can't set codec %s hw params\n", codec_dai->name); @@ -503,7 +516,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (cpu_dai->ops.hw_params) { - ret = cpu_dai->ops.hw_params(substream, params, cpu_dai); + ret = cpu_dai->ops.hw_params(substream, params); if (ret < 0) { printk(KERN_ERR "asoc: interface %s hw params failed\n", cpu_dai->name); @@ -526,11 +539,11 @@ out: platform_err: if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream, cpu_dai); + cpu_dai->ops.hw_free(substream); interface_err: if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream, codec_dai); + codec_dai->ops.hw_free(substream); codec_err: if (machine->ops && machine->ops->hw_free) @@ -548,8 +561,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -570,10 +582,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) /* now free hw params for the DAI's */ if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream, codec_dai); + codec_dai->ops.hw_free(substream); if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream, cpu_dai); + cpu_dai->ops.hw_free(substream); mutex_unlock(&pcm_mutex); return 0; @@ -583,15 +595,14 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card= socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret; if (codec_dai->ops.trigger) { - ret = codec_dai->ops.trigger(substream, cmd, codec_dai); + ret = codec_dai->ops.trigger(substream, cmd); if (ret < 0) return ret; } @@ -603,7 +614,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } if (cpu_dai->ops.trigger) { - ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai); + ret = cpu_dai->ops.trigger(substream, cmd); if (ret < 0) return ret; } @@ -625,8 +636,8 @@ static struct snd_pcm_ops soc_pcm_ops = { static int soc_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; int i; @@ -642,29 +653,29 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot); /* mute any active DAC's */ - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *dai = card->dai_link[i].codec_dai; - if (dai->ops.digital_mute && dai->playback.active) - dai->ops.digital_mute(dai, 1); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; + if (dai->dai_ops.digital_mute && dai->playback.active) + dai->dai_ops.digital_mute(dai, 1); } /* suspend all pcms */ - for (i = 0; i < card->num_links; i++) - snd_pcm_suspend_all(card->dai_link[i].pcm); + for (i = 0; i < machine->num_links; i++) + snd_pcm_suspend_all(machine->dai_link[i].pcm); - if (card->suspend_pre) - card->suspend_pre(pdev, state); + if (machine->suspend_pre) + machine->suspend_pre(pdev, state); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && !cpu_dai->ac97_control) - cpu_dai->suspend(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) + cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) - platform->suspend(cpu_dai); + platform->suspend(pdev, cpu_dai); } /* close any waiting streams and save state */ - run_delayed_work(&card->delayed_work); + run_delayed_work(&socdev->delayed_work); codec->suspend_bias_level = codec->bias_level; for (i = 0; i < codec->num_dai; i++) { @@ -681,14 +692,14 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (codec_dev->suspend) codec_dev->suspend(pdev, state); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && cpu_dai->ac97_control) - cpu_dai->suspend(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) + cpu_dai->suspend(pdev, cpu_dai); } - if (card->suspend_post) - card->suspend_post(pdev, state); + if (machine->suspend_post) + machine->suspend_post(pdev, state); return 0; } @@ -698,11 +709,11 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) */ static void soc_resume_deferred(struct work_struct *work) { - struct snd_soc_card *card = container_of(work, - struct snd_soc_card, - deferred_resume_work); - struct snd_soc_device *socdev = card->socdev; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_device *socdev = container_of(work, + struct snd_soc_device, + deferred_resume_work); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; struct platform_device *pdev = to_platform_device(socdev->dev); @@ -712,15 +723,15 @@ static void soc_resume_deferred(struct work_struct *work) * so userspace apps are blocked from touching us */ - dev_dbg(socdev->dev, "starting resume work\n"); + dev_info(socdev->dev, "starting resume work\n"); - if (card->resume_pre) - card->resume_pre(pdev); + if (machine->resume_pre) + machine->resume_pre(pdev); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && cpu_dai->ac97_control) - cpu_dai->resume(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) + cpu_dai->resume(pdev, cpu_dai); } if (codec_dev->resume) @@ -738,24 +749,24 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *dai = card->dai_link[i].codec_dai; - if (dai->ops.digital_mute && dai->playback.active) - dai->ops.digital_mute(dai, 0); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; + if (dai->dai_ops.digital_mute && dai->playback.active) + dai->dai_ops.digital_mute(dai, 0); } - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && !cpu_dai->ac97_control) - cpu_dai->resume(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) + cpu_dai->resume(pdev, cpu_dai); if (platform->resume) - platform->resume(cpu_dai); + platform->resume(pdev, cpu_dai); } - if (card->resume_post) - card->resume_post(pdev); + if (machine->resume_post) + machine->resume_post(pdev); - dev_dbg(socdev->dev, "resume work completed\n"); + dev_info(socdev->dev, "resume work completed\n"); /* userspace can access us now we are back as we were before */ snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0); @@ -765,12 +776,11 @@ static void soc_resume_deferred(struct work_struct *work) static int soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - dev_dbg(socdev->dev, "scheduling resume work\n"); + dev_info(socdev->dev, "scheduling resume work\n"); - if (!schedule_work(&card->deferred_resume_work)) - dev_err(socdev->dev, "resume work item may be lost\n"); + if (!schedule_work(&socdev->deferred_resume_work)) + dev_err(socdev->dev, "work item may be lost\n"); return 0; } @@ -780,83 +790,23 @@ static int soc_resume(struct platform_device *pdev) #define soc_resume NULL #endif -static void snd_soc_instantiate_card(struct snd_soc_card *card) +/* probes a new socdev */ +static int soc_probe(struct platform_device *pdev) { - struct platform_device *pdev = container_of(card->dev, - struct platform_device, - dev); - struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; - struct snd_soc_platform *platform; - struct snd_soc_dai *dai; - int i, found, ret, ac97; - - if (card->instantiated) - return; - - found = 0; - list_for_each_entry(platform, &platform_list, list) - if (card->platform == platform) { - found = 1; - break; - } - if (!found) { - dev_dbg(card->dev, "Platform %s not registered\n", - card->platform->name); - return; - } - - ac97 = 0; - for (i = 0; i < card->num_links; i++) { - found = 0; - list_for_each_entry(dai, &dai_list, list) - if (card->dai_link[i].cpu_dai == dai) { - found = 1; - break; - } - if (!found) { - dev_dbg(card->dev, "DAI %s not registered\n", - card->dai_link[i].cpu_dai->name); - return; - } - - if (card->dai_link[i].cpu_dai->ac97_control) - ac97 = 1; - } - - /* If we have AC97 in the system then don't wait for the - * codec. This will need revisiting if we have to handle - * systems with mixed AC97 and non-AC97 parts. Only check for - * DAIs currently; we can't do this per link since some AC97 - * codecs have non-AC97 DAIs. - */ - if (!ac97) - for (i = 0; i < card->num_links; i++) { - found = 0; - list_for_each_entry(dai, &dai_list, list) - if (card->dai_link[i].codec_dai == dai) { - found = 1; - break; - } - if (!found) { - dev_dbg(card->dev, "DAI %s not registered\n", - card->dai_link[i].codec_dai->name); - return; - } - } - - /* Note that we do not current check for codec components */ - - dev_dbg(card->dev, "All components present, instantiating\n"); + int ret = 0, i; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - /* Found everything, bring it up */ - if (card->probe) { - ret = card->probe(pdev); + if (machine->probe) { + ret = machine->probe(pdev); if (ret < 0) - return; + return ret; } - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->probe) { ret = cpu_dai->probe(pdev, cpu_dai); if (ret < 0) @@ -877,15 +827,13 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) } /* DAPM stream work */ - INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work); + INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); #ifdef CONFIG_PM /* deferred resume work */ - INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); + INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred); #endif - card->instantiated = 1; - - return; + return 0; platform_err: if (codec_dev->remove) @@ -893,45 +841,15 @@ platform_err: cpu_dai_err: for (i--; i >= 0; i--) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (card->remove) - card->remove(pdev); -} - -/* - * Attempt to initialise any uninitalised cards. Must be called with - * client_mutex. - */ -static void snd_soc_instantiate_cards(void) -{ - struct snd_soc_card *card; - list_for_each_entry(card, &card_list, list) - snd_soc_instantiate_card(card); -} + if (machine->remove) + machine->remove(pdev); -/* probes a new socdev */ -static int soc_probe(struct platform_device *pdev) -{ - int ret = 0; - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - - /* Bodge while we push things out of socdev */ - card->socdev = socdev; - - /* Bodge while we unpick instantiation */ - card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to register card\n"); - return ret; - } - - return 0; + return ret; } /* removes a socdev */ @@ -939,11 +857,11 @@ static int soc_remove(struct platform_device *pdev) { int i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - run_delayed_work(&card->delayed_work); + run_delayed_work(&socdev->delayed_work); if (platform->remove) platform->remove(pdev); @@ -951,16 +869,14 @@ static int soc_remove(struct platform_device *pdev) if (codec_dev->remove) codec_dev->remove(pdev); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (card->remove) - card->remove(pdev); - - snd_soc_unregister_card(card); + if (machine->remove) + machine->remove(pdev); return 0; } @@ -982,8 +898,6 @@ static int soc_new_pcm(struct snd_soc_device *socdev, struct snd_soc_dai_link *dai_link, int num) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *codec_dai = dai_link->codec_dai; struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; struct snd_soc_pcm_runtime *rtd; @@ -1000,8 +914,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, codec_dai->codec = socdev->codec; /* check client and interface hw capabilities */ - sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, - num); + sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name, + get_dai_name(cpu_dai->type), num); if (codec_dai->playback.channels_min) playback = 1; @@ -1019,13 +933,13 @@ static int soc_new_pcm(struct snd_soc_device *socdev, dai_link->pcm = pcm; pcm->private_data = rtd; - soc_pcm_ops.mmap = platform->pcm_ops->mmap; - soc_pcm_ops.pointer = platform->pcm_ops->pointer; - soc_pcm_ops.ioctl = platform->pcm_ops->ioctl; - soc_pcm_ops.copy = platform->pcm_ops->copy; - soc_pcm_ops.silence = platform->pcm_ops->silence; - soc_pcm_ops.ack = platform->pcm_ops->ack; - soc_pcm_ops.page = platform->pcm_ops->page; + soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; + soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; + soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl; + soc_pcm_ops.copy = socdev->platform->pcm_ops->copy; + soc_pcm_ops.silence = socdev->platform->pcm_ops->silence; + soc_pcm_ops.ack = socdev->platform->pcm_ops->ack; + soc_pcm_ops.page = socdev->platform->pcm_ops->page; if (playback) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); @@ -1033,22 +947,24 @@ static int soc_new_pcm(struct snd_soc_device *socdev, if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); - ret = platform->pcm_new(codec->card, codec_dai, pcm); + ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm); if (ret < 0) { printk(KERN_ERR "asoc: platform pcm constructor failed\n"); kfree(rtd); return ret; } - pcm->private_free = platform->pcm_free; + pcm->private_free = socdev->platform->pcm_free; printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; } /* codec register dump */ -static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) +static ssize_t codec_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct snd_soc_device *devdata = dev_get_drvdata(dev); struct snd_soc_codec *codec = devdata->codec; int i, step = 1, count = 0; @@ -1085,110 +1001,8 @@ static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) return count; } -static ssize_t codec_reg_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct snd_soc_device *devdata = dev_get_drvdata(dev); - return soc_codec_reg_show(devdata, buf); -} - static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); -#ifdef CONFIG_DEBUG_FS -static int codec_reg_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - ssize_t ret; - struct snd_soc_codec *codec = file->private_data; - struct device *card_dev = codec->card->dev; - struct snd_soc_device *devdata = card_dev->driver_data; - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - ret = soc_codec_reg_show(devdata, buf); - if (ret >= 0) - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - kfree(buf); - return ret; -} - -static ssize_t codec_reg_write_file(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - char buf[32]; - int buf_size; - char *start = buf; - unsigned long reg, value; - int step = 1; - struct snd_soc_codec *codec = file->private_data; - - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - if (codec->reg_cache_step) - step = codec->reg_cache_step; - - while (*start == ' ') - start++; - reg = simple_strtoul(start, &start, 16); - if ((reg >= codec->reg_cache_size) || (reg % step)) - return -EINVAL; - while (*start == ' ') - start++; - if (strict_strtoul(start, 16, &value)) - return -EINVAL; - codec->write(codec, reg, value); - return buf_size; -} - -static const struct file_operations codec_reg_fops = { - .open = codec_reg_open_file, - .read = codec_reg_read_file, - .write = codec_reg_write_file, -}; - -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ - codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - debugfs_root, codec, - &codec_reg_fops); - if (!codec->debugfs_reg) - printk(KERN_WARNING - "ASoC: Failed to create codec register debugfs file\n"); - - codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, - debugfs_root, - &codec->pop_time); - if (!codec->debugfs_pop_time) - printk(KERN_WARNING - "Failed to create pop time debugfs file\n"); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove(codec->debugfs_pop_time); - debugfs_remove(codec->debugfs_reg); -} - -#else - -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ -} - -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ -} -#endif - /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec @@ -1307,7 +1121,7 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; + struct snd_soc_machine *machine = socdev->machine; int ret = 0, i; mutex_lock(&codec->mutex); @@ -1326,11 +1140,11 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); /* create the pcms */ - for (i = 0; i < card->num_links; i++) { - ret = soc_new_pcm(socdev, &card->dai_link[i], i); + for (i = 0; i < machine->num_links; i++) { + ret = soc_new_pcm(socdev, &machine->dai_link[i], i); if (ret < 0) { printk(KERN_ERR "asoc: can't create pcm %s\n", - card->dai_link[i].stream_name); + machine->dai_link[i].stream_name); mutex_unlock(&codec->mutex); return ret; } @@ -1342,7 +1156,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) EXPORT_SYMBOL_GPL(snd_soc_new_pcms); /** - * snd_soc_init_card - register sound card + * snd_soc_register_card - register sound card * @socdev: the SoC audio device * * Register a SoC sound card. Also registers an AC97 device if the @@ -1350,28 +1164,29 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); * * Returns 0 for success, else error. */ -int snd_soc_init_card(struct snd_soc_device *socdev) +int snd_soc_register_card(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; + struct snd_soc_machine *machine = socdev->machine; int ret = 0, i, ac97 = 0, err = 0; - for (i = 0; i < card->num_links; i++) { - if (card->dai_link[i].init) { - err = card->dai_link[i].init(codec); + for (i = 0; i < machine->num_links; i++) { + if (socdev->machine->dai_link[i].init) { + err = socdev->machine->dai_link[i].init(codec); if (err < 0) { printk(KERN_ERR "asoc: failed to init %s\n", - card->dai_link[i].stream_name); + socdev->machine->dai_link[i].stream_name); continue; } } - if (card->dai_link[i].codec_dai->ac97_control) + if (socdev->machine->dai_link[i].codec_dai->type == + SND_SOC_DAI_AC97_BUS) ac97 = 1; } snprintf(codec->card->shortname, sizeof(codec->card->shortname), - "%s", card->name); + "%s", machine->name); snprintf(codec->card->longname, sizeof(codec->card->longname), - "%s (%s)", card->name, codec->name); + "%s (%s)", machine->name, codec->name); ret = snd_card_register(codec->card); if (ret < 0) { @@ -1401,13 +1216,12 @@ int snd_soc_init_card(struct snd_soc_device *socdev) if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); - soc_init_codec_debugfs(socdev->codec); mutex_unlock(&codec->mutex); out: return ret; } -EXPORT_SYMBOL_GPL(snd_soc_init_card); +EXPORT_SYMBOL_GPL(snd_soc_register_card); /** * snd_soc_free_pcms - free sound card and pcms @@ -1425,11 +1239,10 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #endif mutex_lock(&codec->mutex); - soc_cleanup_codec_debugfs(socdev->codec); #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - if (codec_dai->ac97_control && codec->ac97) { + if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { soc_ac97_dev_unregister(codec); goto free_card; } @@ -1943,8 +1756,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - if (dai->ops.set_sysclk) - return dai->ops.set_sysclk(dai, clk_id, freq, dir); + if (dai->dai_ops.set_sysclk) + return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir); else return -EINVAL; } @@ -1963,8 +1776,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - if (dai->ops.set_clkdiv) - return dai->ops.set_clkdiv(dai, div_id, div); + if (dai->dai_ops.set_clkdiv) + return dai->dai_ops.set_clkdiv(dai, div_id, div); else return -EINVAL; } @@ -1982,8 +1795,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { - if (dai->ops.set_pll) - return dai->ops.set_pll(dai, pll_id, freq_in, freq_out); + if (dai->dai_ops.set_pll) + return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out); else return -EINVAL; } @@ -1992,14 +1805,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); /** * snd_soc_dai_set_fmt - configure DAI hardware audio format. * @dai: DAI + * @clk_id: DAI specific clock ID * @fmt: SND_SOC_DAIFMT_ format value. * * Configures the DAI hardware format and clocking. */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->ops.set_fmt) - return dai->ops.set_fmt(dai, fmt); + if (dai->dai_ops.set_fmt) + return dai->dai_ops.set_fmt(dai, fmt); else return -EINVAL; } @@ -2017,8 +1831,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { - if (dai->ops.set_sysclk) - return dai->ops.set_tdm_slot(dai, mask, slots); + if (dai->dai_ops.set_sysclk) + return dai->dai_ops.set_tdm_slot(dai, mask, slots); else return -EINVAL; } @@ -2033,8 +1847,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); */ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) { - if (dai->ops.set_sysclk) - return dai->ops.set_tristate(dai, tristate); + if (dai->dai_ops.set_sysclk) + return dai->dai_ops.set_tristate(dai, tristate); else return -EINVAL; } @@ -2049,200 +1863,21 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); */ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (dai->ops.digital_mute) - return dai->ops.digital_mute(dai, mute); + if (dai->dai_ops.digital_mute) + return dai->dai_ops.digital_mute(dai, mute); else return -EINVAL; } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); -/** - * snd_soc_register_card - Register a card with the ASoC core - * - * @param card Card to register - * - * Note that currently this is an internal only function: it will be - * exposed to machine drivers after further backporting of ASoC v2 - * registration APIs. - */ -static int snd_soc_register_card(struct snd_soc_card *card) -{ - if (!card->name || !card->dev) - return -EINVAL; - - INIT_LIST_HEAD(&card->list); - card->instantiated = 0; - - mutex_lock(&client_mutex); - list_add(&card->list, &card_list); - snd_soc_instantiate_cards(); - mutex_unlock(&client_mutex); - - dev_dbg(card->dev, "Registered card '%s'\n", card->name); - - return 0; -} - -/** - * snd_soc_unregister_card - Unregister a card with the ASoC core - * - * @param card Card to unregister - * - * Note that currently this is an internal only function: it will be - * exposed to machine drivers after further backporting of ASoC v2 - * registration APIs. - */ -static int snd_soc_unregister_card(struct snd_soc_card *card) -{ - mutex_lock(&client_mutex); - list_del(&card->list); - mutex_unlock(&client_mutex); - - dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); - - return 0; -} - -/** - * snd_soc_register_dai - Register a DAI with the ASoC core - * - * @param dai DAI to register - */ -int snd_soc_register_dai(struct snd_soc_dai *dai) -{ - if (!dai->name) - return -EINVAL; - - /* The device should become mandatory over time */ - if (!dai->dev) - printk(KERN_WARNING "No device for DAI %s\n", dai->name); - - INIT_LIST_HEAD(&dai->list); - - mutex_lock(&client_mutex); - list_add(&dai->list, &dai_list); - snd_soc_instantiate_cards(); - mutex_unlock(&client_mutex); - - pr_debug("Registered DAI '%s'\n", dai->name); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_register_dai); - -/** - * snd_soc_unregister_dai - Unregister a DAI from the ASoC core - * - * @param dai DAI to unregister - */ -void snd_soc_unregister_dai(struct snd_soc_dai *dai) -{ - mutex_lock(&client_mutex); - list_del(&dai->list); - mutex_unlock(&client_mutex); - - pr_debug("Unregistered DAI '%s'\n", dai->name); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); - -/** - * snd_soc_register_dais - Register multiple DAIs with the ASoC core - * - * @param dai Array of DAIs to register - * @param count Number of DAIs - */ -int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = snd_soc_register_dai(&dai[i]); - if (ret != 0) - goto err; - } - - return 0; - -err: - for (i--; i >= 0; i--) - snd_soc_unregister_dai(&dai[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_register_dais); - -/** - * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core - * - * @param dai Array of DAIs to unregister - * @param count Number of DAIs - */ -void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count) -{ - int i; - - for (i = 0; i < count; i++) - snd_soc_unregister_dai(&dai[i]); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); - -/** - * snd_soc_register_platform - Register a platform with the ASoC core - * - * @param platform platform to register - */ -int snd_soc_register_platform(struct snd_soc_platform *platform) -{ - if (!platform->name) - return -EINVAL; - - INIT_LIST_HEAD(&platform->list); - - mutex_lock(&client_mutex); - list_add(&platform->list, &platform_list); - snd_soc_instantiate_cards(); - mutex_unlock(&client_mutex); - - pr_debug("Registered platform '%s'\n", platform->name); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_register_platform); - -/** - * snd_soc_unregister_platform - Unregister a platform from the ASoC core - * - * @param platform platform to unregister - */ -void snd_soc_unregister_platform(struct snd_soc_platform *platform) -{ - mutex_lock(&client_mutex); - list_del(&platform->list); - mutex_unlock(&client_mutex); - - pr_debug("Unregistered platform '%s'\n", platform->name); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); - static int __devinit snd_soc_init(void) { -#ifdef CONFIG_DEBUG_FS - debugfs_root = debugfs_create_dir("asoc", NULL); - if (IS_ERR(debugfs_root) || !debugfs_root) { - printk(KERN_WARNING - "ASoC: Failed to create debugfs directory\n"); - debugfs_root = NULL; - } -#endif - + printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); return platform_driver_register(&soc_driver); } -static void __exit snd_soc_exit(void) +static void snd_soc_exit(void) { -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(debugfs_root); -#endif platform_driver_unregister(&soc_driver); } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 61d7d85aa578..7351db9606e4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -37,6 +37,7 @@ #include <linux/bitops.h> #include <linux/platform_device.h> #include <linux/jiffies.h> +#include <linux/debugfs.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -66,13 +67,17 @@ static int dapm_status = 1; module_param(dapm_status, int, 0); MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); -static void pop_wait(u32 pop_time) +static struct dentry *asoc_debugfs; + +static u32 pop_time; + +static void pop_wait(void) { if (pop_time) schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); } -static void pop_dbg(u32 pop_time, const char *fmt, ...) +static void pop_dbg(const char *fmt, ...) { va_list args; @@ -80,7 +85,7 @@ static void pop_dbg(u32 pop_time, const char *fmt, ...) if (pop_time) { vprintk(fmt, args); - pop_wait(pop_time); + pop_wait(); } va_end(args); @@ -225,11 +230,10 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget) change = old != new; if (change) { - pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n", - widget->name, widget->power ? "on" : "off", - codec->pop_time); + pop_dbg("pop test %s : %s in %d ms\n", widget->name, + widget->power ? "on" : "off", pop_time); snd_soc_write(codec, widget->reg, new); - pop_wait(codec->pop_time); + pop_wait(); } pr_debug("reg %x old %x new %x change %d\n", widget->reg, old, new, change); @@ -289,7 +293,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *w) { int i, ret = 0; - size_t name_len; + char name[32]; struct snd_soc_dapm_path *path; /* add kcontrol */ @@ -303,16 +307,11 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, continue; /* add dapm control with long name */ - name_len = 2 + strlen(w->name) - + strlen(w->kcontrols[i].name); - path->long_name = kmalloc(name_len, GFP_KERNEL); + snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); + path->long_name = kstrdup (name, GFP_KERNEL); if (path->long_name == NULL) return -ENOMEM; - snprintf(path->long_name, name_len, "%s %s", - w->name, w->kcontrols[i].name); - path->long_name[name_len - 1] = '\0'; - path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, path->long_name); ret = snd_ctl_add(codec->card, path->kcontrol); @@ -822,9 +821,23 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { + int ret = 0; + if (!dapm_status) return 0; - return device_create_file(dev, &dev_attr_dapm_widget); + + ret = device_create_file(dev, &dev_attr_dapm_widget); + if (ret != 0) + return ret; + + asoc_debugfs = debugfs_create_dir("asoc", NULL); + if (!IS_ERR(asoc_debugfs) && asoc_debugfs) + debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs, + &pop_time); + else + asoc_debugfs = NULL; + + return 0; } static void snd_soc_dapm_sys_remove(struct device *dev) @@ -832,6 +845,9 @@ static void snd_soc_dapm_sys_remove(struct device *dev) if (dapm_status) { device_remove_file(dev, &dev_attr_dapm_widget); } + + if (asoc_debugfs) + debugfs_remove_recursive(asoc_debugfs); } /* free all dapm widgets and resources */ @@ -991,6 +1007,28 @@ err: } /** + * snd_soc_dapm_connect_input - connect dapm widgets + * @codec: audio codec + * @sink: name of target widget + * @control: mixer control name + * @source: name of source name + * + * Connects 2 dapm widgets together via a named audio path. The sink is + * the widget receiving the audio signal, whilst the source is the sender + * of the audio signal. + * + * This function has been deprecated in favour of snd_soc_dapm_add_routes(). + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, + const char *control, const char *source) +{ + return snd_soc_dapm_add_route(codec, sink, control, source); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); + +/** * snd_soc_dapm_add_routes - Add routes between DAPM widgets * @codec: codec * @route: audio routes @@ -1402,11 +1440,11 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, enum snd_soc_bias_level level) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; + struct snd_soc_machine *machine = socdev->machine; int ret = 0; - if (card->set_bias_level) - ret = card->set_bias_level(card, level); + if (machine->set_bias_level) + ret = machine->set_bias_level(machine, level); if (ret == 0 && codec->set_bias_level) ret = codec->set_bias_level(codec, level); diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c index ccd763dd7167..798ca124da58 100644 --- a/sound/usb/caiaq/caiaq-control.c +++ b/sound/usb/caiaq/caiaq-control.c @@ -247,56 +247,69 @@ static struct caiaq_controller a8dj_controller[] = { { "Software lock", 40 } }; -static int __devinit add_controls(struct caiaq_controller *c, int num, - struct snd_usb_caiaqdev *dev) -{ - int i, ret; - struct snd_kcontrol *kc; - - for (i = 0; i < num; i++, c++) { - kcontrol_template.name = c->name; - kcontrol_template.private_value = c->index; - kc = snd_ctl_new1(&kcontrol_template, dev); - ret = snd_ctl_add(dev->chip.card, kc); - if (ret < 0) - return ret; - } - - return 0; -} - int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) { - int ret = 0; + int i; + struct snd_kcontrol *kc; switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): - ret = add_controls(ak1_controller, - ARRAY_SIZE(ak1_controller), dev); + for (i = 0; i < ARRAY_SIZE(ak1_controller); i++) { + struct caiaq_controller *c = ak1_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): - ret = add_controls(rk2_controller, - ARRAY_SIZE(rk2_controller), dev); + for (i = 0; i < ARRAY_SIZE(rk2_controller); i++) { + struct caiaq_controller *c = rk2_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): - ret = add_controls(rk3_controller, - ARRAY_SIZE(rk3_controller), dev); + for (i = 0; i < ARRAY_SIZE(rk3_controller); i++) { + struct caiaq_controller *c = rk3_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): - ret = add_controls(kore_controller, - ARRAY_SIZE(kore_controller), dev); + for (i = 0; i < ARRAY_SIZE(kore_controller); i++) { + struct caiaq_controller *c = kore_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): - ret = add_controls(a8dj_controller, - ARRAY_SIZE(a8dj_controller), dev); + for (i = 0; i < ARRAY_SIZE(a8dj_controller); i++) { + struct caiaq_controller *c = a8dj_controller + i; + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + snd_ctl_add(dev->chip.card, kc); + } + break; } - return ret; + return 0; } diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index b143ef7152f7..83175083e50f 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -42,7 +42,7 @@ #endif MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.9"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," |