Sound updates for 3.9-rc1

The biggest change in this update is the unification of HD-audio codec
 parsers.  Now the HD-audio codec is parsed in a generic parser code
 which is invoked by each HD-audio codec driver.  Some background
 information is found in David Henningsson's blog entry:
   http://voices.canonical.com/david.henningsson/2013/01/18/upcoming-changes-to-the-intel-hda-drivers/
 
 Other than that, some random updates/fixes like USB-audio and a bunch
 of small AoC updates as usual.
 
 Highlights:
 
 - Unification of HD-audio parser code (aka generic parser)
 
 - Support of new Intel HD-audio controller, new IDT codecs
 
 - Fixes for HD-audio HDMI audio hotplug
 
 - Haswell HDMI audio fixup
 
 - Support of Creative CA0132 DSP code
 
 - A few fixes of HDSP driver
 
 - USB-audio fix for Roland A-PRO, M-Audio FT C600
 
 - Support PM for aloop driver (and fixes Oops)
 
 - Compress API updates for gapless playback support
 
 For ASoC part:
 
 - Support for a wider range of hardware in the compressed stream code
 
 - The ability to mute capture streams as well as playback streams while
   inactive
 
 - DT support for AK4642, FSI, Samsung I2S and WM8962
 
 - AC'97 support for Tegra
 
 - New driver for max98090, replacing the stub which was there
 
 - A new driver from Dialog
 
 Note that due to dependencies, DTification of DMA support for Samsung
 platforms (used only by the and I2S driver and SPI) is merged here as
 well.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iQIcBAABAgAGBQJRJjy2AAoJEGwxgFQ9KSmk4EoP/RRslXfGAb+lrWeehmh9oHQL
 P4JX+Cgv4OFFxaVjU7IgdjBCCnUNZoQ/Nm8wnpDbF+qP7DTcryPnuwWH8oaHLFSJ
 +knbbbOShC6hxUzd+ZbxQpEn+4mupSC9+egzczz0wcK1kzAf8CO/rj17t3VxsoW/
 Qa1yCWy6jbOmLu3JDpJTPyLfwA3x4/i3ViyTYfqgLP5kQHZZiv1eA9b682HFX9xQ
 uDQipb040k7wBLoeZosR8iF/EDuPHls8H2ASCmZw0K2scZgBok0SkI6BBwsCg2z3
 VbD9EkZmobRHwmubfDV1yCti050YnwGUbrN9tNpdSdv2cogKCkkxQ+zL8PX6Qf0l
 D1neA9JJPhSMx5fufDnG5oTghx/XlHsTJKmrJNu8Gr/14pAmSbNF8iIOFfYju++2
 LlpHLlwS4hxNYY0W3iAFTXi50BUng38tdhBCyZTgN2tSHaTwtdWvrVyizjpUa18N
 onjvFtceULtudddosJWkaKUSqHLN/CWmIWXufucfjxEk5exXjPBMhYTsvhmM3I5D
 zrK0GxUQqey7RToa48Sxs0iL269labUwH/8H1iMTL3/9UCCOqVRKR3X7NdGi3xtK
 EiEiCeNoZX8PojGqSEkmRifOJ19gBxchZDNO4ruct0Omc4Jn/nOlHbi4jXghgr9H
 D62m5PriiCnyBswjzKaX
 =nIPc
 -----END PGP SIGNATURE-----

Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "The biggest change in this update is the unification of HD-audio codec
  parsers.  Now the HD-audio codec is parsed in a generic parser code
  which is invoked by each HD-audio codec driver.

  Some background information is found in David Henningsson's blog
  entry:

      http://voices.canonical.com/david.henningsson/2013/01/18/upcoming-changes-to-the-intel-hda-drivers/

  Other than that, some random updates/fixes like USB-audio and a bunch
  of small AoC updates as usual.

  Highlights:

   - Unification of HD-audio parser code (aka generic parser)

   - Support of new Intel HD-audio controller, new IDT codecs

   - Fixes for HD-audio HDMI audio hotplug

   - Haswell HDMI audio fixup

   - Support of Creative CA0132 DSP code

   - A few fixes of HDSP driver

   - USB-audio fix for Roland A-PRO, M-Audio FT C600

   - Support PM for aloop driver (and fixes Oops)

   - Compress API updates for gapless playback support

  For ASoC part:

   - Support for a wider range of hardware in the compressed stream code

   - The ability to mute capture streams as well as playback streams
     while inactive

   - DT support for AK4642, FSI, Samsung I2S and WM8962

   - AC'97 support for Tegra

   - New driver for max98090, replacing the stub which was there

   - A new driver from Dialog

  Note that due to dependencies, DTification of DMA support for Samsung
  platforms (used only by the and I2S driver and SPI) is merged here as
  well."

Fix up trivial conflict in drivers/spi/spi-s3c64xx.c due to removed code
being changed.

* tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (453 commits)
  ALSA: usb: Fix Processing Unit Descriptor parsers
  ALSA: hda - hdmi: Notify userspace when ELD control changes
  ALSA: hda - hdmi: Protect ELD buffer
  ALSA: hda - hdmi: Refactor hdmi_eld into parsed_hdmi_eld
  ALSA: hda - hdmi: Do not expose eld data when eld is invalid
  ALSA: hda - hdmi: ELD shouldn't be valid after unplug
  ALSA: hda - Fix the silent speaker output on Fujitsu S7020 laptop
  ALSA: hda - add quirks for mute LED on two HP machines
  ALSA: usb/quirks, fix out-of-bounds access
  ASoC: codecs: Add da7213 codec
  ALSA: au88x0 - Define channel map for au88x0
  ALSA: compress: add support for gapless playback
  ALSA: hda - Remove speaker clicks on CX20549
  ALSA: hda - Disable runtime PM for Intel 5 Series/3400
  ALSA: hda - Increase badness for missing multi-io
  ASoC: arizona: Automatically manage input mutes
  ALSA: hda - Fix broken workaround for HDMI/SPDIF conflicts
  ALSA: hda/ca0132 - Add missing \n to debug prints
  ALSA: hda/ca0132 - Fix type of INVALID_CHIP_ADDRESS
  ALSA: hda - update documentation for no-primary-hp fixup
  ...
This commit is contained in:
Linus Torvalds 2013-02-21 11:34:25 -08:00
commit 460dc1eecf
175 changed files with 25631 additions and 18988 deletions

View File

@ -871,9 +871,8 @@
<para>
This function itself doesn't allocate the data space. The data
must be allocated manually beforehand, and its pointer is passed
as the argument. This pointer is used as the
(<parameter>chip</parameter> identifier in the above example)
for the instance.
as the argument. This pointer (<parameter>chip</parameter> in the
above example) is used as the identifier for the instance.
</para>
<para>
@ -2304,7 +2303,7 @@ struct _snd_pcm_runtime {
<constant>SNDRV_PCM_INFO_XXX</constant>. Here, at least, you
have to specify whether the mmap is supported and which
interleaved format is supported.
When the is supported, add the
When the hardware supports mmap, add the
<constant>SNDRV_PCM_INFO_MMAP</constant> flag here. When the
hardware supports the interleaved or the non-interleaved
formats, <constant>SNDRV_PCM_INFO_INTERLEAVED</constant> or
@ -2898,7 +2897,7 @@ struct _snd_pcm_runtime {
<para>
When the pcm supports the pause operation (given in the info
field of the hardware table), the <constant>PAUSE_PUSE</constant>
field of the hardware table), the <constant>PAUSE_PUSH</constant>
and <constant>PAUSE_RELEASE</constant> commands must be
handled here, too. The former is the command to pause the pcm,
and the latter to restart the pcm again.
@ -3085,7 +3084,7 @@ struct _snd_pcm_runtime {
<section id="pcm-interface-interrupt-handler-timer">
<title>High frequency timer interrupts</title>
<para>
This happense when the hardware doesn't generate interrupts
This happens when the hardware doesn't generate interrupts
at the period boundary but issues timer interrupts at a fixed
timer rate (e.g. es1968 or ymfpci drivers).
In this case, you need to check the current hardware
@ -3250,49 +3249,6 @@ struct _snd_pcm_runtime {
<example>
<title>Example of Hardware Constraints for Channels</title>
<programlisting>
<![CDATA[
static int hw_rule_format_by_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_mask fmt;
snd_mask_any(&fmt); /* Init the struct */
if (c->min < 2) {
fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
return snd_mask_refine(f, &fmt);
}
return 0;
}
]]>
</programlisting>
</example>
</para>
<para>
Then you need to call this function to add your rule:
<informalexample>
<programlisting>
<![CDATA[
snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
hw_rule_channels_by_format, 0, SNDRV_PCM_HW_PARAM_FORMAT,
-1);
]]>
</programlisting>
</informalexample>
</para>
<para>
The rule function is called when an application sets the number of
channels. But an application can set the format before the number of
channels. Thus you also need to define the inverse rule:
<example>
<title>Example of Hardware Constraints for Channels</title>
<programlisting>
<![CDATA[
static int hw_rule_channels_by_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
@ -3314,6 +3270,50 @@ struct _snd_pcm_runtime {
</programlisting>
</example>
</para>
<para>
Then you need to call this function to add your rule:
<informalexample>
<programlisting>
<![CDATA[
snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
hw_rule_channels_by_format, NULL,
SNDRV_PCM_HW_PARAM_FORMAT, -1);
]]>
</programlisting>
</informalexample>
</para>
<para>
The rule function is called when an application sets the PCM
format, and it refines the number of channels accordingly.
But an application may set the number of channels before
setting the format. Thus you also need to define the inverse rule:
<example>
<title>Example of Hardware Constraints for Formats</title>
<programlisting>
<![CDATA[
static int hw_rule_format_by_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_mask fmt;
snd_mask_any(&fmt); /* Init the struct */
if (c->min < 2) {
fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
return snd_mask_refine(f, &fmt);
}
return 0;
}
]]>
</programlisting>
</example>
</para>
<para>
...and in the open callback:
@ -3321,8 +3321,8 @@ struct _snd_pcm_runtime {
<programlisting>
<![CDATA[
snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
hw_rule_format_by_channels, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-1);
hw_rule_format_by_channels, NULL,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
]]>
</programlisting>
</informalexample>

View File

@ -0,0 +1,17 @@
AK4642 I2C transmitter
This device supports I2C mode only.
Required properties:
- compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648"
- reg : The chip select number on the I2C bus
Example:
&i2c {
ak4648: ak4648@0x12 {
compatible = "asahi-kasei,ak4642";
reg = <0x12>;
};
};

View File

@ -20,6 +20,18 @@ Optional properties:
!RESET pin
- cirrus,amuteb-eq-bmutec: When given, the Codec's AMUTEB=BMUTEC flag
is enabled.
- cirrus,enable-soft-reset:
The CS4271 requires its LRCLK and MCLK to be stable before its RESET
line is de-asserted. That also means that clocks cannot be changed
without putting the chip back into hardware reset, which also requires
a complete re-initialization of all registers.
One (undocumented) workaround is to assert and de-assert the PDN bit
in the MODE2 register. This workaround can be enabled with this DT
property.
Note that this is not needed in case the clocks are stable
throughout the entire runtime of the codec.
Examples:

View File

@ -0,0 +1,51 @@
NVIDIA Tegra audio complex
Required properties:
- compatible : "nvidia,tegra-audio-wm9712"
- nvidia,model : The user-visible name of this sound complex.
- nvidia,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the WM9712's pins, and the jacks on the board:
WM9712 pins:
* MONOOUT
* HPOUTL
* HPOUTR
* LOUT2
* ROUT2
* OUT3
* LINEINL
* LINEINR
* PHONE
* PCBEEP
* MIC1
* MIC2
* Mic Bias
Board connectors:
* Headphone
* LineIn
* Mic
- nvidia,ac97-controller : The phandle of the Tegra AC97 controller
Example:
sound {
compatible = "nvidia,tegra-audio-wm9712-colibri_t20",
"nvidia,tegra-audio-wm9712";
nvidia,model = "Toradex Colibri T20";
nvidia,audio-routing =
"Headphone", "HPOUTL",
"Headphone", "HPOUTR",
"LineIn", "LINEINL",
"LineIn", "LINEINR",
"Mic", "MIC1";
nvidia,ac97-controller = <&ac97>;
};

View File

@ -0,0 +1,22 @@
NVIDIA Tegra 20 AC97 controller
Required properties:
- compatible : "nvidia,tegra20-ac97"
- reg : Should contain AC97 controller registers location and length
- interrupts : Should contain AC97 interrupt
- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
request selector for the AC97 controller
- nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number
of the GPIO used to reset the external AC97 codec
- nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number
of the GPIO corresponding with the AC97 DAP _FS line
Example:
ac97@70002000 {
compatible = "nvidia,tegra20-ac97";
reg = <0x70002000 0x200>;
interrupts = <0 81 0x04>;
nvidia,dma-request-selector = <&apbdma 12>;
nvidia,codec-reset-gpio = <&gpio 170 0>;
nvidia,codec-sync-gpio = <&gpio 120 0>;
};

View File

@ -6,6 +6,52 @@ Required properties:
- ti,mcbsp: phandle for the McBSP node
- ti,codec: phandle for the twl4030 audio node
Optional properties:
- ti,mcbsp-voice: phandle for the McBSP node connected to the voice port of twl
- ti, jack-det-gpio: Jack detect GPIO
- ti,audio-routing: List of connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source.
If the routing is not provided all possible connection will be available
Available audio endpoints for the audio-routing table:
Board connectors:
* Headset Stereophone
* Earpiece Spk
* Handsfree Spk
* Ext Spk
* Main Mic
* Sub Mic
* Headset Mic
* Carkit Mic
* Digital0 Mic
* Digital1 Mic
* Line In
twl4030 pins:
* HSOL
* HSOR
* EARPIECE
* HFL
* HFR
* PREDRIVEL
* PREDRIVER
* CARKITL
* CARKITR
* MAINMIC
* SUBMIC
* HSMIC
* DIGIMIC0
* DIGIMIC1
* CARKITMIC
* AUXL
* AUXR
* Headset Mic Bias
* Mic Bias 1 /* Used for Main Mic or Digimic0 */
* Mic Bias 2 /* Used for Sub Mic or Digimic1 */
Example:
sound {

View File

@ -0,0 +1,26 @@
Renesas FSI
Required properties:
- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi"
- reg : Should contain the register physical address and length
- interrupts : Should contain FSI interrupt
- fsia,spdif-connection : FSI is connected by S/PDFI
- fsia,stream-mode-support : FSI supports 16bit stream mode.
- fsia,use-internal-clock : FSI uses internal clock when master mode.
- fsib,spdif-connection : same as fsia
- fsib,stream-mode-support : same as fsia
- fsib,use-internal-clock : same as fsia
Example:
sh_fsi2: sh_fsi2@0xec230000 {
compatible = "renesas,sh_fsi2";
reg = <0xec230000 0x400>;
interrupts = <0 146 0x4>;
fsia,spdif-connection;
fsia,stream-mode-support;
fsia,use-internal-clock;
};

View File

@ -0,0 +1,14 @@
Samsung SMDK audio complex
Required properties:
- compatible : "samsung,smdk-wm8994"
- samsung,i2s-controller: The phandle of the Samsung I2S0 controller
- samsung,audio-codec: The phandle of the WM8994 audio codec
Example:
sound {
compatible = "samsung,smdk-wm8994";
samsung,i2s-controller = <&i2s0>;
samsung,audio-codec = <&wm8994>;
};

View File

@ -0,0 +1,63 @@
* Samsung I2S controller
Required SoC Specific Properties:
- compatible : "samsung,i2s-v5"
- reg: physical base address of the controller and length of memory mapped
region.
- dmas: list of DMA controller phandle and DMA request line ordered pairs.
- dma-names: identifier string for each DMA request line in the dmas property.
These strings correspond 1:1 with the ordered pairs in dmas.
Optional SoC Specific Properties:
- samsung,supports-6ch: If the I2S Primary sound source has 5.1 Channel
support, this flag is enabled.
- samsung,supports-rstclr: This flag should be set if I2S software reset bit
control is required. When this flag is set I2S software reset bit will be
enabled or disabled based on need.
- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA,
then this flag is enabled.
- samsung,idma-addr: Internal DMA register base address of the audio
sub system(used in secondary sound source).
Required Board Specific Properties:
- gpios: The gpio specifier for data out,data in, LRCLK, CDCLK and SCLK
interface lines. The format of the gpio specifier depends on the gpio
controller.
The syntax of samsung gpio specifier is
<[phandle of the gpio controller node]
[pin number within the gpio controller]
[mux function]
[flags and pull up/down]
[drive strength]>
Example:
- SoC Specific Portion:
i2s@03830000 {
compatible = "samsung,i2s-v5";
reg = <0x03830000 0x100>;
dmas = <&pdma0 10
&pdma0 9
&pdma0 8>;
dma-names = "tx", "rx", "tx-sec";
samsung,supports-6ch;
samsung,supports-rstclr;
samsung,supports-secdai;
samsung,idma-addr = <0x03000000>;
};
- Board Specific Portion:
i2s@03830000 {
gpios = <&gpz 0 2 0 0>, /* I2S_0_SCLK */
<&gpz 1 2 0 0>, /* I2S_0_CDCLK */
<&gpz 2 2 0 0>, /* I2S_0_LRCK */
<&gpz 3 2 0 0>, /* I2S_0_SDI */
<&gpz 4 2 0 0>, /* I2S_0_SDO[1] */
<&gpz 5 2 0 0>, /* I2S_0_SDO[2] */
<&gpz 6 2 0 0>; /* I2S_0_SDO[3] */
};

View File

@ -11,6 +11,12 @@ Optional properties:
- gpio-reset - gpio pin number used for codec reset
- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
- ai3x-micbias-vg - MicBias Voltage required.
1 - MICBIAS output is powered to 2.0V,
2 - MICBIAS output is powered to 2.5V,
3 - MICBIAS output is connected to AVDD,
If this node is not mentioned or if the value is incorrect, then MicBias
is powered down.
Example:

View File

@ -0,0 +1,16 @@
WM8962 audio CODEC
This device supports I2C only.
Required properties:
- compatible : "wlf,wm8962"
- reg : the I2C address of the device.
Example:
codec: wm8962@1a {
compatible = "wlf,wm8962";
reg = <0x1a>;
};

View File

@ -890,8 +890,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
power_save - Automatic power-saving timeout (in second, 0 =
disable)
power_save_controller - Reset HD-audio controller in power-saving mode
(default = on)
power_save_controller - Support runtime D3 of HD-audio controller
(-1 = on for supported chip (default), false = off,
true = force to on even for unsupported hardware)
align_buffer_size - Force rounding of buffer/period sizes to multiples
of 128 bytes. This is more efficient in terms of memory
access but isn't required by the HDA spec and prevents

View File

@ -53,7 +53,7 @@ ALC882/883/885/888/889
acer-aspire-8930g Acer Aspire 8330G/6935G
acer-aspire Acer Aspire others
inv-dmic Inverted internal mic workaround
no-primary-hp VAIO Z workaround (for fixed speaker DAC)
no-primary-hp VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC)
ALC861/660
==========

View File

@ -176,14 +176,14 @@ 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 overcome such a situation.
When the matching preset model is found in the white-list, the driver
assumes the static configuration of that preset and builds the mixer
elements and PCM streams 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.
The preset model (or recently called as "fix-up") is provided
basically to overcome such a situation. When the matching preset
model is found in the white-list, the driver assumes the static
configuration of that preset with the correct pin setup, etc.
Thus, if you have a newer machine with a slightly different PCI SSID
(or codec 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 (and codec-) 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"
@ -199,17 +199,12 @@ non-working HD-audio hardware is to check HD-audio codec and several
different `model` option values. If you have any 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.
There are a few special model option values:
- when 'nofixup' is passed, the device-specific fixups in the codec
parser are skipped.
- when `generic` is passed, the codec-specific parser is skipped and
only the generic parser is used.
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -387,9 +382,8 @@ init_verbs::
(separated with a space).
hints::
Shows / stores hint strings for codec parsers for any use.
Its format is `key = value`. For example, passing `hp_detect = yes`
to IDT/STAC codec parser will result in the disablement of the
headphone detection.
Its format is `key = value`. For example, passing `jack_detect = no`
will disable the jack detection of the machine completely.
init_pin_configs::
Shows the initial pin default config values set by BIOS.
driver_pin_configs::
@ -421,6 +415,61 @@ re-configure based on that state, run like below:
------------------------------------------------------------------------
Hint Strings
~~~~~~~~~~~~
The codec parser have several switches and adjustment knobs for
matching better with the actual codec or device behavior. Many of
them can be adjusted dynamically via "hints" strings as mentioned in
the section above. For example, by passing `jack_detect = no` string
via sysfs or a patch file, you can disable the jack detection, thus
the codec parser will skip the features like auto-mute or mic
auto-switch. As a boolean value, either `yes`, `no`, `true`, `false`,
`1` or `0` can be passed.
The generic parser supports the following hints:
- jack_detect (bool): specify whether the jack detection is available
at all on this machine; default true
- inv_jack_detect (bool): indicates that the jack detection logic is
inverted
- trigger_sense (bool): indicates that the jack detection needs the
explicit call of AC_VERB_SET_PIN_SENSE verb
- inv_eapd (bool): indicates that the EAPD is implemented in the
inverted logic
- pcm_format_first (bool): sets the PCM format before the stream tag
and channel ID
- sticky_stream (bool): keep the PCM format, stream tag and ID as long
as possible; default true
- spdif_status_reset (bool): reset the SPDIF status bits at each time
the SPDIF stream is set up
- pin_amp_workaround (bool): the output pin may have multiple amp
values
- single_adc_amp (bool): ADCs can have only single input amps
- auto_mute (bool): enable/disable the headphone auto-mute feature;
default true
- auto_mic (bool): enable/disable the mic auto-switch feature; default
true
- line_in_auto_switch (bool): enable/disable the line-in auto-switch
feature; default false
- need_dac_fix (bool): limits the DACs depending on the channel count
- primary_hp (bool): probe headphone jacks as the primary outputs;
default true
- multi_cap_vol (bool): provide multiple capture volumes
- inv_dmic_split (bool): provide split internal mic volume/switch for
phase-inverted digital mics
- indep_hp (bool): provide the independent headphone PCM stream and
the corresponding mixer control, if available
- add_stereo_mix_input (bool): add the stereo mix (analog-loopback
mix) to the input mux if available
- add_out_jack_modes (bool): add "xxx Jack Mode" enum controls to each
output jack for allowing to change the headphone amp capability
- add_in_jack_modes (bool): add "xxx Jack Mode" enum controls to each
input jack for allowing to change the mic bias vref
- power_down_unused (bool): power down the unused widgets
- mixer_nid (int): specifies the widget NID of the analog-loopback
mixer
Early Patching
~~~~~~~~~~~~~~
When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a
@ -445,7 +494,7 @@ A patch file is a plain text file which looks like below:
0x20 0x400 0xff
[hint]
hp_detect = yes
jack_detect = no
------------------------------------------------------------------------
The file needs to have a line `[codec]`. The next line should contain
@ -531,6 +580,13 @@ cable is unplugged. Thus, if you hear noises, suspect first the
power-saving. See /sys/module/snd_hda_intel/parameters/power_save to
check the current value. If it's non-zero, the feature is turned on.
The recent kernel supports the runtime PM for the HD-audio controller
chip, too. It means that the HD-audio controller is also powered up /
down dynamically. The feature is enabled only for certain controller
chips like Intel LynxPoint. You can enable/disable this feature
forcibly by setting `power_save_controller` option, which is also
available at /sys/module/snd_hda_intel/parameters directory.
Tracepoints
~~~~~~~~~~~
@ -587,8 +643,9 @@ The latest development codes for HD-audio are found on sound git tree:
- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
The master branch or for-next branches can be used as the main
development branches in general while the HD-audio specific patches
are committed in topic/hda branch.
development branches in general while the development for the current
and next kernels are found in for-linus and for-next branches,
respectively.
If you are using the latest Linus tree, it'd be better to pull the
above GIT tree onto it. If you are using the older kernels, an easy
@ -699,7 +756,11 @@ 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:
The hda-verb program is included now in alsa-tools:
- git://git.alsa-project.org/alsa-tools.git
Also, the old stand-alone package is found in the ftp directory:
- ftp://ftp.suse.com/pub/people/tiwai/misc/
@ -777,3 +838,18 @@ A git repository is available:
See README file in the tarball for more details about hda-emu
program.
hda-jack-retask
~~~~~~~~~~~~~~~
hda-jack-retask is a user-friendly GUI program to manipulate the
HD-audio pin control for jack retasking. If you have a problem about
the jack assignment, try this program and check whether you can get
useful results. Once when you figure out the proper pin assignment,
it can be fixed either in the driver code statically or via passing a
firmware patch file (see "Early Patching" section).
The program is included in alsa-tools now:
- git://git.alsa-project.org/alsa-tools.git

View File

@ -145,6 +145,52 @@ Modifications include:
- Addition of encoding options when required (derived from OpenMAX IL)
- Addition of rateControlSupported (missing in OpenMAX AL)
Gapless Playback
================
When playing thru an album, the decoders have the ability to skip the encoder
delay and padding and directly move from one track content to another. The end
user can perceive this as gapless playback as we dont have silence while
switching from one track to another
Also, there might be low-intensity noises due to encoding. Perfect gapless is
difficult to reach with all types of compressed data, but works fine with most
music content. The decoder needs to know the encoder delay and encoder padding.
So we need to pass this to DSP. This metadata is extracted from ID3/MP4 headers
and are not present by default in the bitstream, hence the need for a new
interface to pass this information to the DSP. Also DSP and userspace needs to
switch from one track to another and start using data for second track.
The main additions are:
- set_metadata
This routine sets the encoder delay and encoder padding. This can be used by
decoder to strip the silence. This needs to be set before the data in the track
is written.
- set_next_track
This routine tells DSP that metadata and write operation sent after this would
correspond to subsequent track
- partial drain
This is called when end of file is reached. The userspace can inform DSP that
EOF is reached and now DSP can start skipping padding delay. Also next write
data would belong to next track
Sequence flow for gapless would be:
- Open
- Get caps / codec caps
- Set params
- Set metadata of the first track
- Fill data of the first track
- Trigger start
- User-space finished sending all,
- Indicaite next track data by sending set_next_track
- Set metadata of the next track
- then call partial_drain to flush most of buffer in DSP
- Fill data of the next track
- DSP switches to second track
(note: order for partial_drain and write for next track can be reversed as well)
Not supported:
- Support for VoIP/circuit-switched calls is not the target of this

View File

@ -49,6 +49,11 @@
compatible = "samsung,s524ad0xd1";
reg = <0x51>;
};
wm8994: wm8994@1a {
compatible = "wlf,wm8994";
reg = <0x1a>;
};
};
i2c@121D0000 {
@ -204,4 +209,25 @@
samsung,mfc-r = <0x43000000 0x800000>;
samsung,mfc-l = <0x51000000 0x800000>;
};
i2s0: i2s@03830000 {
gpios = <&gpz 0 2 0 0>, <&gpz 1 2 0 0>, <&gpz 2 2 0 0>,
<&gpz 3 2 0 0>, <&gpz 4 2 0 0>, <&gpz 5 2 0 0>,
<&gpz 6 2 0 0>;
};
i2s1: i2s@12D60000 {
status = "disabled";
};
i2s2: i2s@12D70000 {
status = "disabled";
};
sound {
compatible = "samsung,smdk-wm8994";
samsung,i2s-controller = <&i2s0>;
samsung,audio-codec = <&wm8994>;
};
};

View File

@ -211,8 +211,9 @@
compatible = "samsung,exynos4210-spi";
reg = <0x12d20000 0x100>;
interrupts = <0 66 0>;
tx-dma-channel = <&pdma0 5>; /* preliminary */
rx-dma-channel = <&pdma0 4>; /* preliminary */
dmas = <&pdma0 5
&pdma0 4>;
dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
};
@ -221,8 +222,9 @@
compatible = "samsung,exynos4210-spi";
reg = <0x12d30000 0x100>;
interrupts = <0 67 0>;
tx-dma-channel = <&pdma1 5>; /* preliminary */
rx-dma-channel = <&pdma1 4>; /* preliminary */
dmas = <&pdma1 5
&pdma1 4>;
dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
};
@ -231,8 +233,9 @@
compatible = "samsung,exynos4210-spi";
reg = <0x12d40000 0x100>;
interrupts = <0 68 0>;
tx-dma-channel = <&pdma0 7>; /* preliminary */
rx-dma-channel = <&pdma0 6>; /* preliminary */
dmas = <&pdma0 7
&pdma0 6>;
dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
};
@ -269,6 +272,35 @@
#size-cells = <0>;
};
i2s0: i2s@03830000 {
compatible = "samsung,i2s-v5";
reg = <0x03830000 0x100>;
dmas = <&pdma0 10
&pdma0 9
&pdma0 8>;
dma-names = "tx", "rx", "tx-sec";
samsung,supports-6ch;
samsung,supports-rstclr;
samsung,supports-secdai;
samsung,idma-addr = <0x03000000>;
};
i2s1: i2s@12D60000 {
compatible = "samsung,i2s-v5";
reg = <0x12D60000 0x100>;
dmas = <&pdma1 12
&pdma1 11>;
dma-names = "tx", "rx";
};
i2s2: i2s@12D70000 {
compatible = "samsung,i2s-v5";
reg = <0x12D70000 0x100>;
dmas = <&pdma0 12
&pdma0 11>;
dma-names = "tx", "rx";
};
amba {
#address-cells = <1>;
#size-cells = <1>;

View File

@ -104,6 +104,12 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL),
OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000,
"exynos-tmu", NULL),
OF_DEV_AUXDATA("samsung,i2s-v5", 0x03830000,
"samsung-i2s.0", NULL),
OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D60000,
"samsung-i2s.1", NULL),
OF_DEV_AUXDATA("samsung,i2s-v5", 0x12D70000,
"samsung-i2s.2", NULL),
{},
};

View File

@ -53,17 +53,25 @@ static unsigned long ac97_reset_config[] = {
GPIO95_AC97_nRESET,
};
void pxa27x_assert_ac97reset(int reset_gpio, int on)
void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio)
{
/*
* This helper function is used to work around a bug in the pxa27x's
* ac97 controller during a warm reset. The configuration of the
* reset_gpio is changed as follows:
* to_gpio == true: configured to generic output gpio and driven high
* to_gpio == false: configured to ac97 controller alt fn AC97_nRESET
*/
if (reset_gpio == 113)
pxa2xx_mfp_config(on ? &ac97_reset_config[0] :
&ac97_reset_config[1], 1);
pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[0] :
&ac97_reset_config[1], 1);
if (reset_gpio == 95)
pxa2xx_mfp_config(on ? &ac97_reset_config[2] :
&ac97_reset_config[3], 1);
pxa2xx_mfp_config(to_gpio ? &ac97_reset_config[2] :
&ac97_reset_config[3], 1);
}
EXPORT_SYMBOL_GPL(pxa27x_assert_ac97reset);
EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset);
/* Crystal clock: 13MHz */
#define BASE_CLK 13000000

View File

@ -657,14 +657,8 @@ static struct platform_device lcdc_device = {
/* FSI */
#define IRQ_FSI evt2irq(0x1840)
static struct sh_fsi_platform_info fsi_info = {
.port_a = {
.flags = SH_FSI_BRS_INV,
},
.port_b = {
.flags = SH_FSI_BRS_INV |
SH_FSI_BRM_INV |
SH_FSI_LRS_INV |
SH_FSI_CLK_CPG |
.flags = SH_FSI_CLK_CPG |
SH_FSI_FMT_SPDIF,
},
};
@ -692,21 +686,21 @@ static struct platform_device fsi_device = {
},
};
static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
.fmt = SND_SOC_DAIFMT_LEFT_J,
.codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
.cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
.sysclk = 11289600,
};
static struct asoc_simple_card_info fsi2_ak4643_info = {
.name = "AK4643",
.card = "FSI2A-AK4643",
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
.codec_dai = "ak4642-hifi",
.init = &fsi2_ak4643_init_info,
.daifmt = SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "fsia-dai",
.fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
.fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
static struct platform_device fsi_ak4643_device = {
@ -815,18 +809,18 @@ static struct platform_device lcdc1_device = {
},
};
static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
.cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
};
static struct asoc_simple_card_info fsi2_hdmi_info = {
.name = "HDMI",
.card = "FSI2B-HDMI",
.cpu_dai = "fsib-dai",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
.codec_dai = "sh_mobile_hdmi-hifi",
.init = &fsi2_hdmi_init_info,
.cpu_dai = {
.name = "fsib-dai",
.fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "sh_mobile_hdmi-hifi",
},
};
static struct platform_device fsi_hdmi_device = {

View File

@ -806,21 +806,21 @@ static struct platform_device fsi_device = {
};
/* FSI-WM8978 */
static struct asoc_simple_dai_init_info fsi_wm8978_init_info = {
.fmt = SND_SOC_DAIFMT_I2S,
.codec_daifmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
.cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
.sysclk = 12288000,
};
static struct asoc_simple_card_info fsi_wm8978_info = {
.name = "wm8978",
.card = "FSI2A-WM8978",
.cpu_dai = "fsia-dai",
.codec = "wm8978.0-001a",
.platform = "sh_fsi2",
.codec_dai = "wm8978-hifi",
.init = &fsi_wm8978_init_info,
.daifmt = SND_SOC_DAIFMT_I2S,
.cpu_dai = {
.name = "fsia-dai",
.fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "wm8978-hifi",
.fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF,
.sysclk = 12288000,
},
};
static struct platform_device fsi_wm8978_device = {
@ -832,18 +832,18 @@ static struct platform_device fsi_wm8978_device = {
};
/* FSI-HDMI */
static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
.cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
};
static struct asoc_simple_card_info fsi2_hdmi_info = {
.name = "HDMI",
.card = "FSI2B-HDMI",
.cpu_dai = "fsib-dai",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
.codec_dai = "sh_mobile_hdmi-hifi",
.init = &fsi2_hdmi_init_info,
.cpu_dai = {
.name = "fsib-dai",
.fmt = SND_SOC_DAIFMT_CBM_CFM,
},
.codec_dai = {
.name = "sh_mobile_hdmi-hifi",
},
};
static struct platform_device fsi_hdmi_device = {

View File

@ -525,21 +525,21 @@ static struct platform_device fsi_device = {
},
};
static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = {
.fmt = SND_SOC_DAIFMT_LEFT_J,
.codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
.cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
.sysclk = 11289600,
};
static struct asoc_simple_card_info fsi2_ak4648_info = {
.name = "AK4648",
.card = "FSI2A-AK4648",
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi2",
.codec_dai = "ak4642-hifi",
.init = &fsi2_ak4648_init_info,
.daifmt = SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "fsia-dai",
.fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
.fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
static struct platform_device fsi_ak4648_device = {

View File

@ -502,18 +502,18 @@ static struct platform_device hdmi_lcdc_device = {
},
};
static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
.cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
};
static struct asoc_simple_card_info fsi2_hdmi_info = {
.name = "HDMI",
.card = "FSI2B-HDMI",
.cpu_dai = "fsib-dai",
.codec = "sh-mobile-hdmi",
.platform = "sh_fsi2",
.codec_dai = "sh_mobile_hdmi-hifi",
.init = &fsi2_hdmi_init_info,
.cpu_dai = {
.name = "fsib-dai",
.fmt = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "sh_mobile_hdmi-hifi",
},
};
static struct platform_device fsi_hdmi_device = {
@ -858,16 +858,12 @@ static struct platform_device leds_device = {
#define IRQ_FSI evt2irq(0x1840)
static struct sh_fsi_platform_info fsi_info = {
.port_a = {
.flags = SH_FSI_BRS_INV,
.tx_id = SHDMA_SLAVE_FSIA_TX,
.rx_id = SHDMA_SLAVE_FSIA_RX,
},
.port_b = {
.flags = SH_FSI_BRS_INV |
SH_FSI_BRM_INV |
SH_FSI_LRS_INV |
SH_FSI_CLK_CPG |
SH_FSI_FMT_SPDIF,
.flags = SH_FSI_CLK_CPG |
SH_FSI_FMT_SPDIF,
}
};
@ -896,21 +892,21 @@ static struct platform_device fsi_device = {
},
};
static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
.fmt = SND_SOC_DAIFMT_LEFT_J,
.codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
.cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
.sysclk = 11289600,
};
static struct asoc_simple_card_info fsi2_ak4643_info = {
.name = "AK4643",
.card = "FSI2A-AK4643",
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
.codec_dai = "ak4642-hifi",
.init = &fsi2_ak4643_init_info,
.daifmt = SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "fsia-dai",
.fmt = SND_SOC_DAIFMT_CBS_CFS,
},
.codec_dai = {
.name = "ak4642-hifi",
.fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
static struct platform_device fsi_ak4643_device = {

View File

@ -19,7 +19,8 @@
#include <mach/dma.h>
static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
struct samsung_dma_req *param)
struct samsung_dma_req *param,
struct device *dev, char *ch_name)
{
dma_cap_mask_t mask;
void *filter_param;
@ -33,7 +34,12 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
*/
filter_param = (dma_ch == DMACH_DT_PROP) ?
(void *)param->dt_dmach_prop : (void *)dma_ch;
return (unsigned)dma_request_channel(mask, pl330_filter, filter_param);
if (dev->of_node)
return (unsigned)dma_request_slave_channel(dev, ch_name);
else
return (unsigned)dma_request_channel(mask, pl330_filter,
filter_param);
}
static int samsung_dmadev_release(unsigned ch, void *param)

View File

@ -39,7 +39,8 @@ struct samsung_dma_config {
};
struct samsung_dma_ops {
unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param);
unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param,
struct device *dev, char *ch_name);
int (*release)(unsigned ch, void *param);
int (*config)(unsigned ch, struct samsung_dma_config *param);
int (*prepare)(unsigned ch, struct samsung_dma_prep *param);

View File

@ -36,7 +36,8 @@ static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
}
static unsigned s3c_dma_request(enum dma_ch dma_ch,
struct samsung_dma_req *param)
struct samsung_dma_req *param,
struct device *dev, char *ch_name)
{
struct cb_data *data;

View File

@ -887,12 +887,6 @@ static struct platform_device camera_devices[] = {
};
/* FSI */
static struct sh_fsi_platform_info fsi_info = {
.port_b = {
.flags = SH_FSI_BRS_INV,
},
};
static struct resource fsi_resources[] = {
[0] = {
.name = "FSI",
@ -911,25 +905,22 @@ static struct platform_device fsi_device = {
.id = 0,
.num_resources = ARRAY_SIZE(fsi_resources),
.resource = fsi_resources,
.dev = {
.platform_data = &fsi_info,
},
};
static struct asoc_simple_dai_init_info fsi_da7210_init_info = {
.fmt = SND_SOC_DAIFMT_I2S,
.codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
.cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
};
static struct asoc_simple_card_info fsi_da7210_info = {
.name = "DA7210",
.card = "FSIB-DA7210",
.cpu_dai = "fsib-dai",
.codec = "da7210.0-001a",
.platform = "sh_fsi.0",
.codec_dai = "da7210-hifi",
.init = &fsi_da7210_init_info,
.daifmt = SND_SOC_DAIFMT_I2S,
.cpu_dai = {
.name = "fsib-dai",
.fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "da7210-hifi",
.fmt = SND_SOC_DAIFMT_CBM_CFM,
},
};
static struct platform_device fsi_da7210_device = {

View File

@ -279,12 +279,6 @@ static struct platform_device ceu1_device = {
/* FSI */
/* change J20, J21, J22 pin to 1-2 connection to use slave mode */
static struct sh_fsi_platform_info fsi_info = {
.port_a = {
.flags = SH_FSI_BRS_INV,
},
};
static struct resource fsi_resources[] = {
[0] = {
.name = "FSI",
@ -303,26 +297,23 @@ static struct platform_device fsi_device = {
.id = 0,
.num_resources = ARRAY_SIZE(fsi_resources),
.resource = fsi_resources,
.dev = {
.platform_data = &fsi_info,
},
};
static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = {
.fmt = SND_SOC_DAIFMT_LEFT_J,
.codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
.cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
.sysclk = 11289600,
};
static struct asoc_simple_card_info fsi_ak4642_info = {
.name = "AK4642",
.card = "FSIA-AK4642",
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
.codec_dai = "ak4642-hifi",
.init = &fsi2_ak4642_init_info,
.daifmt = SND_SOC_DAIFMT_LEFT_J,
.cpu_dai = {
.name = "fsia-dai",
.fmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_IB_NF,
},
.codec_dai = {
.name = "ak4642-hifi",
.fmt = SND_SOC_DAIFMT_CBM_CFM,
.sysclk = 11289600,
},
};
static struct platform_device fsi_ak4642_device = {

View File

@ -192,7 +192,7 @@ config ICS932S401
config ATMEL_SSC
tristate "Device driver for Atmel SSC peripheral"
depends on AVR32 || ARCH_AT91
depends on HAS_IOMEM
---help---
This option enables device driver support for Atmel Synchronized
Serial Communication peripheral (SSC).

View File

@ -175,7 +175,7 @@ static int ssc_probe(struct platform_device *pdev)
/* disable all interrupts */
clk_enable(ssc->clk);
ssc_writel(ssc->regs, IDR, ~0UL);
ssc_writel(ssc->regs, IDR, -1);
ssc_readl(ssc->regs, SR);
clk_disable(ssc->clk);

View File

@ -134,7 +134,6 @@ struct s3c64xx_spi_dma_data {
unsigned ch;
enum dma_transfer_direction direction;
enum dma_ch dmach;
struct property *dma_prop;
};
/**
@ -319,16 +318,15 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
{
struct samsung_dma_req req;
struct device *dev = &sdd->pdev->dev;
sdd->ops = samsung_dma_get_ops();
req.cap = DMA_SLAVE;
req.client = &s3c64xx_spi_dma_client;
req.dt_dmach_prop = sdd->rx_dma.dma_prop;
sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req);
req.dt_dmach_prop = sdd->tx_dma.dma_prop;
sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req);
sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
return 1;
}
@ -1053,49 +1051,6 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
flush_fifo(sdd);
}
static int s3c64xx_spi_get_dmares(
struct s3c64xx_spi_driver_data *sdd, bool tx)
{
struct platform_device *pdev = sdd->pdev;
struct s3c64xx_spi_dma_data *dma_data;
struct property *prop;
struct resource *res;
char prop_name[15], *chan_str;
if (tx) {
dma_data = &sdd->tx_dma;
dma_data->direction = DMA_MEM_TO_DEV;
chan_str = "tx";
} else {
dma_data = &sdd->rx_dma;
dma_data->direction = DMA_DEV_TO_MEM;
chan_str = "rx";
}
if (!sdd->pdev->dev.of_node) {
res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
if (!res) {
dev_err(&pdev->dev, "Unable to get SPI-%s dma resource\n",
chan_str);
return -ENXIO;
}
dma_data->dmach = res->start;
return 0;
}
sprintf(prop_name, "%s-dma-channel", chan_str);
prop = of_find_property(pdev->dev.of_node, prop_name, NULL);
if (!prop) {
dev_err(&pdev->dev, "%s dma channel property not specified\n",
chan_str);
return -ENXIO;
}
dma_data->dmach = DMACH_DT_PROP;
dma_data->dma_prop = prop;
return 0;
}
#ifdef CONFIG_OF
static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
{
@ -1194,6 +1149,7 @@ static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
static int s3c64xx_spi_probe(struct platform_device *pdev)
{
struct resource *mem_res;
struct resource *res;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
struct spi_master *master;
@ -1252,13 +1208,26 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
sdd->cur_bpw = 8;
ret = s3c64xx_spi_get_dmares(sdd, true);
if (ret)
goto err0;
if (!sdd->pdev->dev.of_node) {
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "Unable to get SPI tx dma "
"resource\n");
return -ENXIO;
}
sdd->tx_dma.dmach = res->start;
ret = s3c64xx_spi_get_dmares(sdd, false);
if (ret)
goto err0;
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "Unable to get SPI rx dma "
"resource\n");
return -ENXIO;
}
sdd->rx_dma.dmach = res->start;
}
sdd->tx_dma.direction = DMA_MEM_TO_DEV;
sdd->rx_dma.direction = DMA_DEV_TO_MEM;
master->dev.of_node = pdev->dev.of_node;
master->bus_num = sdd->port_id;

View File

@ -62,6 +62,8 @@
#define ARIZONA_MAX_OUTPUT 6
#define ARIZONA_MAX_AIF 3
#define ARIZONA_HAP_ACT_ERM 0
#define ARIZONA_HAP_ACT_LRA 2
@ -96,6 +98,13 @@ struct arizona_pdata {
/** Pin state for GPIO pins */
int gpio_defaults[ARIZONA_MAX_GPIO];
/**
* Maximum number of channels clocks will be generated for,
* useful for systems where and I2S bus with multiple data
* lines is mastered.
*/
int max_channels_clocked[ARIZONA_MAX_AIF];
/** GPIO for mic detection polarity */
int micd_pol_gpio;

View File

@ -71,6 +71,8 @@ struct snd_compr_runtime {
* @runtime: pointer to runtime structure
* @device: device pointer
* @direction: stream direction, playback/recording
* @metadata_set: metadata set flag, true when set
* @next_track: has userspace signall next track transistion, true when set
* @private_data: pointer to DSP private data
*/
struct snd_compr_stream {
@ -79,6 +81,8 @@ struct snd_compr_stream {
struct snd_compr_runtime *runtime;
struct snd_compr *device;
enum snd_compr_direction direction;
bool metadata_set;
bool next_track;
void *private_data;
};
@ -110,6 +114,10 @@ struct snd_compr_ops {
struct snd_compr_params *params);
int (*get_params)(struct snd_compr_stream *stream,
struct snd_codec *params);
int (*set_metadata)(struct snd_compr_stream *stream,
struct snd_compr_metadata *metadata);
int (*get_metadata)(struct snd_compr_stream *stream,
struct snd_compr_metadata *metadata);
int (*trigger)(struct snd_compr_stream *stream, int cmd);
int (*pointer)(struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp);

View File

@ -394,8 +394,11 @@ void __snd_printk(unsigned int level, const char *file, int line,
#else /* !CONFIG_SND_DEBUG */
#define snd_printd(fmt, args...) do { } while (0)
#define _snd_printd(level, fmt, args...) do { } while (0)
__printf(1, 2)
static inline void snd_printd(const char *format, ...) {}
__printf(2, 3)
static inline void _snd_printd(int level, const char *format, ...) {}
#define snd_BUG() do { } while (0)
static inline int __snd_bug_on(int cond)
{
@ -416,7 +419,8 @@ static inline int __snd_bug_on(int cond)
#define snd_printdd(format, args...) \
__snd_printk(2, __FILE__, __LINE__, format, ##args)
#else
#define snd_printdd(format, args...) do { } while (0)
__printf(1, 2)
static inline void snd_printdd(const char *format, ...) {}
#endif
@ -454,6 +458,7 @@ struct snd_pci_quirk {
#define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val) \
{_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), \
.value = (val), .name = (xname)}
#define snd_pci_quirk_name(q) ((q)->name)
#else
#define SND_PCI_QUIRK(vend,dev,xname,val) \
{_SND_PCI_QUIRK_ID(vend, dev), .value = (val)}
@ -461,6 +466,7 @@ struct snd_pci_quirk {
{_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), .value = (val)}
#define SND_PCI_QUIRK_VENDOR(vend, xname, val) \
{_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val)}
#define snd_pci_quirk_name(q) ""
#endif
const struct snd_pci_quirk *

View File

@ -20,6 +20,21 @@
struct cs4271_platform_data {
int gpio_nreset; /* GPIO driving Reset pin, if any */
bool amutec_eq_bmutec; /* flag to enable AMUTEC=BMUTEC */
/*
* The CS4271 requires its LRCLK and MCLK to be stable before its RESET
* line is de-asserted. That also means that clocks cannot be changed
* without putting the chip back into hardware reset, which also requires
* a complete re-initialization of all registers.
*
* One (undocumented) workaround is to assert and de-assert the PDN bit
* in the MODE2 register. This workaround can be enabled with the
* following flag.
*
* Note that this is not needed in case the clocks are stable
* throughout the entire runtime of the codec.
*/
bool enable_soft_reset;
};
#endif /* __CS4271_H */

52
include/sound/da7213.h Normal file
View File

@ -0,0 +1,52 @@
/*
* da7213.h - DA7213 ASoC Codec Driver Platform Data
*
* Copyright (c) 2013 Dialog Semiconductor
*
* Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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 _DA7213_PDATA_H
#define _DA7213_PDATA_H
enum da7213_micbias_voltage {
DA7213_MICBIAS_1_6V = 0,
DA7213_MICBIAS_2_2V = 1,
DA7213_MICBIAS_2_5V = 2,
DA7213_MICBIAS_3_0V = 3,
};
enum da7213_dmic_data_sel {
DA7213_DMIC_DATA_LRISE_RFALL = 0,
DA7213_DMIC_DATA_LFALL_RRISE = 1,
};
enum da7213_dmic_samplephase {
DA7213_DMIC_SAMPLE_ON_CLKEDGE = 0,
DA7213_DMIC_SAMPLE_BETWEEN_CLKEDGE = 1,
};
enum da7213_dmic_clk_rate {
DA7213_DMIC_CLK_3_0MHZ = 0,
DA7213_DMIC_CLK_1_5MHZ = 1,
};
struct da7213_platform_data {
/* Mic Bias voltage */
enum da7213_micbias_voltage micbias1_lvl;
enum da7213_micbias_voltage micbias2_lvl;
/* DMIC config */
enum da7213_dmic_data_sel dmic_data_sel;
enum da7213_dmic_samplephase dmic_samplephase;
enum da7213_dmic_clk_rate dmic_clk_rate;
/* MCLK squaring config */
bool mclk_squaring;
};
#endif /* _DA7213_PDATA_H */

29
include/sound/max98090.h Executable file
View File

@ -0,0 +1,29 @@
/*
* Platform data for MAX98090
*
* Copyright 2011-2012 Maxim Integrated Products
*
* 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.
*
*/
#ifndef __SOUND_MAX98090_PDATA_H__
#define __SOUND_MAX98090_PDATA_H__
/* codec platform data */
struct max98090_pdata {
/* Analog/digital microphone configuration:
* 0 = analog microphone input (normal setting)
* 1 = digital microphone input
*/
unsigned int digmic_left_mode:1;
unsigned int digmic_right_mode:1;
unsigned int digmic_3_mode:1;
unsigned int digmic_4_mode:1;
};
#endif

View File

@ -37,7 +37,7 @@ struct snd_dma_device {
#ifndef snd_dma_pci_data
#define snd_dma_pci_data(pci) (&(pci)->dev)
#define snd_dma_isa_data() NULL
#define snd_dma_continuous_data(x) ((struct device *)(unsigned long)(x))
#define snd_dma_continuous_data(x) ((struct device *)(__force unsigned long)(x))
#endif

View File

@ -1,16 +0,0 @@
/*
* Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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_SAIF_H__
#define __SOUND_SAIF_H__
struct mxs_saif_platform_data {
bool master_mode; /* if true use master mode */
int master_id; /* id of the master if in slave mode */
};
#endif

View File

@ -11,82 +11,20 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define FSI_PORT_A 0
#define FSI_PORT_B 1
#include <linux/clk.h>
#include <sound/soc.h>
/*
* flags format
*
* 0x00000CBA
*
* A: inversion
* B: format mode
* C: chip specific
* D: clock selecter if master mode
* flags
*/
/* A: clock inversion */
#define SH_FSI_INVERSION_MASK 0x0000000F
#define SH_FSI_LRM_INV (1 << 0)
#define SH_FSI_BRM_INV (1 << 1)
#define SH_FSI_LRS_INV (1 << 2)
#define SH_FSI_BRS_INV (1 << 3)
/* B: format mode */
#define SH_FSI_FMT_MASK 0x000000F0
#define SH_FSI_FMT_DAI (0 << 4)
#define SH_FSI_FMT_SPDIF (1 << 4)
/* C: chip specific */
#define SH_FSI_OPTION_MASK 0x00000F00
#define SH_FSI_ENABLE_STREAM_MODE (1 << 8) /* for 16bit data */
/* D: clock selecter if master mode */
#define SH_FSI_CLK_MASK 0x0000F000
#define SH_FSI_CLK_EXTERNAL (0 << 12)
#define SH_FSI_CLK_CPG (1 << 12) /* FSIxCK + FSI-DIV */
/*
* set_rate return value
*
* see ACKMD/BPFMD on
* ACK_MD (FSI2)
* CKG1 (FSI)
*
* err : return value < 0
* no change : return value == 0
* change xMD : return value > 0
*
* 0x-00000AB
*
* A: ACKMD value
* B: BPFMD value
*/
#define SH_FSI_ACKMD_MASK (0xF << 0)
#define SH_FSI_ACKMD_512 (1 << 0)
#define SH_FSI_ACKMD_256 (2 << 0)
#define SH_FSI_ACKMD_128 (3 << 0)
#define SH_FSI_ACKMD_64 (4 << 0)
#define SH_FSI_ACKMD_32 (5 << 0)
#define SH_FSI_BPFMD_MASK (0xF << 4)
#define SH_FSI_BPFMD_512 (1 << 4)
#define SH_FSI_BPFMD_256 (2 << 4)
#define SH_FSI_BPFMD_128 (3 << 4)
#define SH_FSI_BPFMD_64 (4 << 4)
#define SH_FSI_BPFMD_32 (5 << 4)
#define SH_FSI_BPFMD_16 (6 << 4)
#define SH_FSI_FMT_SPDIF (1 << 0) /* spdif for HDMI */
#define SH_FSI_ENABLE_STREAM_MODE (1 << 1) /* for 16bit data */
#define SH_FSI_CLK_CPG (1 << 2) /* FSIxCK + FSI-DIV */
struct sh_fsi_port_info {
unsigned long flags;
int tx_id;
int rx_id;
int (*set_rate)(struct device *dev, int rate, int enable);
};
struct sh_fsi_platform_info {

View File

@ -14,21 +14,21 @@
#include <sound/soc.h>
struct asoc_simple_dai_init_info {
struct asoc_simple_dai {
const char *name;
unsigned int fmt;
unsigned int cpu_daifmt;
unsigned int codec_daifmt;
unsigned int sysclk;
};
struct asoc_simple_card_info {
const char *name;
const char *card;
const char *cpu_dai;
const char *codec;
const char *platform;
const char *codec_dai;
struct asoc_simple_dai_init_info *init; /* for snd_link.init */
unsigned int daifmt;
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
/* used in simple-card.c */
struct snd_soc_dai_link snd_link;

View File

@ -45,7 +45,7 @@ struct snd_compr_stream;
* sending or receiving PCM data in a frame. This can be used to save power.
*/
#define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */
#define SND_SOC_DAIFMT_GATED (2 << 4) /* clock is gated */
#define SND_SOC_DAIFMT_GATED (0 << 4) /* clock is gated */
/*
* DAI hardware signal inversions.
@ -53,7 +53,7 @@ struct snd_compr_stream;
* Specifies whether the DAI can also support inverted clocks for the specified
* format.
*/
#define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */
#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */
#define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */
#define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */
#define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */
@ -126,7 +126,8 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
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);
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
int direction);
struct snd_soc_dai_ops {
/*
@ -157,6 +158,7 @@ struct snd_soc_dai_ops {
* Called by soc-core to minimise any pops.
*/
int (*digital_mute)(struct snd_soc_dai *dai, int mute);
int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
/*
* ALSA PCM audio operations - all optional.

View File

@ -906,8 +906,8 @@ struct snd_soc_dai_link {
struct snd_pcm_hw_params *params);
/* machine stream operations */
struct snd_soc_ops *ops;
struct snd_soc_compr_ops *compr_ops;
const struct snd_soc_ops *ops;
const struct snd_soc_compr_ops *compr_ops;
};
struct snd_soc_codec_conf {
@ -1171,6 +1171,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card,
const char *propname);
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
const char *prefix);
#include <sound/soc-dai.h>

View File

@ -46,6 +46,13 @@ enum {
AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15
};
enum aic3x_micbias_voltage {
AIC3X_MICBIAS_OFF = 0,
AIC3X_MICBIAS_2_0V = 1,
AIC3X_MICBIAS_2_5V = 2,
AIC3X_MICBIAS_AVDDV = 3,
};
struct aic3x_setup_data {
unsigned int gpio_func[2];
};
@ -53,6 +60,9 @@ struct aic3x_setup_data {
struct aic3x_pdata {
int gpio_reset; /* < 0 if not used */
struct aic3x_setup_data *setup;
/* Selects the micbias voltage */
enum aic3x_micbias_voltage micbias_vg;
};
#endif

View File

@ -15,9 +15,6 @@ struct wm2000_platform_data {
/** Filename for system-specific image to download to device. */
const char *download_file;
/** Divide MCLK by 2 for system clock? */
unsigned int mclkdiv2:1;
/** Disable speech clarity enhancement, for use when an
* external algorithm is used. */
unsigned int speech_enh_disable:1;

View File

@ -12,6 +12,7 @@
#define __LINUX_SND_WM2200_H
#define WM2200_GPIO_SET 0x10000
#define WM2200_MAX_MICBIAS 2
enum wm2200_in_mode {
WM2200_IN_SE = 0,
@ -25,6 +26,24 @@ enum wm2200_dmic_sup {
WM2200_DMIC_SUP_MICBIAS2 = 2,
};
enum wm2200_mbias_lvl {
WM2200_MBIAS_LVL_1V5 = 1,
WM2200_MBIAS_LVL_1V8 = 2,
WM2200_MBIAS_LVL_1V9 = 3,
WM2200_MBIAS_LVL_2V0 = 4,
WM2200_MBIAS_LVL_2V2 = 5,
WM2200_MBIAS_LVL_2V4 = 6,
WM2200_MBIAS_LVL_2V5 = 7,
WM2200_MBIAS_LVL_2V6 = 8,
};
struct wm2200_micbias {
enum wm2200_mbias_lvl mb_lvl; /** Regulated voltage */
unsigned int discharge:1; /** Actively discharge */
unsigned int fast_start:1; /** Enable aggressive startup ramp rate */
unsigned int bypass:1; /** Use bypass mode */
};
struct wm2200_pdata {
int reset; /** GPIO controlling /RESET, if any */
int ldo_ena; /** GPIO controlling LODENA, if any */
@ -35,7 +54,8 @@ struct wm2200_pdata {
enum wm2200_in_mode in_mode[3];
enum wm2200_dmic_sup dmic_sup[3];
int micbias_cfg[2]; /** Register value to configure MICBIAS */
/** MICBIAS configurations */
struct wm2200_micbias micbias[WM2200_MAX_MICBIAS];
};
#endif

View File

@ -384,14 +384,16 @@ static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_de
int protocol)
{
__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
return desc->baSourceID[desc->bNrInPins + control_size];
return *(uac_processing_unit_bmControls(desc, protocol)
+ control_size);
}
static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc,
int protocol)
{
__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
return &desc->baSourceID[desc->bNrInPins + control_size + 1];
return uac_processing_unit_bmControls(desc, protocol)
+ control_size + 1;
}
/* 4.5.2 Class-Specific AS Interface Descriptor */

View File

@ -30,7 +30,7 @@
#include <sound/compress_params.h>
#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 1)
/**
* struct snd_compressed_buffer: compressed buffer
* @fragment_size: size of buffer fragment in bytes
@ -121,6 +121,27 @@ struct snd_compr_codec_caps {
struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
};
/**
* @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the
* end of the track
* @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the
* beginning of the track
*/
enum {
SNDRV_COMPRESS_ENCODER_PADDING = 1,
SNDRV_COMPRESS_ENCODER_DELAY = 2,
};
/**
* struct snd_compr_metadata: compressed stream metadata
* @key: key id
* @value: key value
*/
struct snd_compr_metadata {
__u32 key;
__u32 value[8];
};
/**
* compress path ioctl definitions
* SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
@ -145,6 +166,10 @@ struct snd_compr_codec_caps {
struct snd_compr_codec_caps)
#define SNDRV_COMPRESS_SET_PARAMS _IOW('C', 0x12, struct snd_compr_params)
#define SNDRV_COMPRESS_GET_PARAMS _IOR('C', 0x13, struct snd_codec)
#define SNDRV_COMPRESS_SET_METADATA _IOW('C', 0x14,\
struct snd_compr_metadata)
#define SNDRV_COMPRESS_GET_METADATA _IOWR('C', 0x15,\
struct snd_compr_metadata)
#define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x20, struct snd_compr_tstamp)
#define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail)
#define SNDRV_COMPRESS_PAUSE _IO('C', 0x30)
@ -152,10 +177,14 @@ struct snd_compr_codec_caps {
#define SNDRV_COMPRESS_START _IO('C', 0x32)
#define SNDRV_COMPRESS_STOP _IO('C', 0x33)
#define SNDRV_COMPRESS_DRAIN _IO('C', 0x34)
#define SNDRV_COMPRESS_NEXT_TRACK _IO('C', 0x35)
#define SNDRV_COMPRESS_PARTIAL_DRAIN _IO('C', 0x36)
/*
* TODO
* 1. add mmap support
*
*/
#define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */
#define SND_COMPR_TRIGGER_NEXT_TRACK 8
#define SND_COMPR_TRIGGER_PARTIAL_DRAIN 9
#endif

View File

@ -34,7 +34,7 @@ static struct clk *ac97_clk;
static struct clk *ac97conf_clk;
static int reset_gpio;
extern void pxa27x_assert_ac97reset(int reset_gpio, int on);
extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
/*
* Beware PXA27x bugs:
@ -140,10 +140,10 @@ static inline void pxa_ac97_warm_pxa27x(void)
gsr_bits = 0;
/* warm reset broken on Bulverde, so manually keep AC97 reset high */
pxa27x_assert_ac97reset(reset_gpio, 1);
pxa27x_configure_ac97reset(reset_gpio, true);
udelay(10);
GCR |= GCR_WARM_RST;
pxa27x_assert_ac97reset(reset_gpio, 0);
pxa27x_configure_ac97reset(reset_gpio, false);
udelay(500);
}
@ -358,7 +358,7 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
__func__, ret);
goto err_conf;
}
pxa27x_assert_ac97reset(reset_gpio, 0);
pxa27x_configure_ac97reset(reset_gpio, false);
ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
if (IS_ERR(ac97conf_clk)) {

View File

@ -144,16 +144,17 @@ static int snd_compr_free(struct inode *inode, struct file *f)
return 0;
}
static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
struct snd_compr_tstamp *tstamp)
{
if (!stream->ops->pointer)
return;
return -ENOTSUPP;
stream->ops->pointer(stream, tstamp);
pr_debug("dsp consumed till %d total %d bytes\n",
tstamp->byte_offset, tstamp->copied_total);
stream->runtime->hw_pointer = tstamp->byte_offset;
stream->runtime->total_bytes_transferred = tstamp->copied_total;
return 0;
}
static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
@ -161,7 +162,9 @@ static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
{
long avail_calc; /*this needs to be signed variable */
memset(avail, 0, sizeof(*avail));
snd_compr_update_tstamp(stream, &avail->tstamp);
/* Still need to return avail even if tstamp can't be filled in */
/* FIXME: This needs to be different for capture stream,
available is # of compressed data, for playback it's
@ -483,6 +486,8 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
if (retval)
goto out;
stream->runtime->state = SNDRV_PCM_STATE_SETUP;
stream->metadata_set = false;
stream->next_track = false;
} else {
return -EPERM;
}
@ -514,14 +519,60 @@ out:
return retval;
}
static int
snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_compr_metadata metadata;
int retval;
if (!stream->ops->get_metadata)
return -ENXIO;
if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
return -EFAULT;
retval = stream->ops->get_metadata(stream, &metadata);
if (retval != 0)
return retval;
if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata)))
return -EFAULT;
return 0;
}
static int
snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_compr_metadata metadata;
int retval;
if (!stream->ops->set_metadata)
return -ENXIO;
/*
* we should allow parameter change only when stream has been
* opened not in other cases
*/
if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
return -EFAULT;
retval = stream->ops->set_metadata(stream, &metadata);
stream->metadata_set = true;
return retval;
}
static inline int
snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
{
struct snd_compr_tstamp tstamp;
struct snd_compr_tstamp tstamp = {0};
int ret;
snd_compr_update_tstamp(stream, &tstamp);
return copy_to_user((struct snd_compr_tstamp __user *)arg,
&tstamp, sizeof(tstamp)) ? -EFAULT : 0;
ret = snd_compr_update_tstamp(stream, &tstamp);
if (ret == 0)
ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
&tstamp, sizeof(tstamp)) ? -EFAULT : 0;
return ret;
}
static int snd_compr_pause(struct snd_compr_stream *stream)
@ -594,6 +645,44 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
return retval;
}
static int snd_compr_next_track(struct snd_compr_stream *stream)
{
int retval;
/* only a running stream can transition to next track */
if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
return -EPERM;
/* you can signal next track isf this is intended to be a gapless stream
* and current track metadata is set
*/
if (stream->metadata_set == false)
return -EPERM;
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK);
if (retval != 0)
return retval;
stream->metadata_set = false;
stream->next_track = true;
return 0;
}
static int snd_compr_partial_drain(struct snd_compr_stream *stream)
{
int retval;
if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
stream->runtime->state == SNDRV_PCM_STATE_SETUP)
return -EPERM;
/* stream can be drained only when next track has been signalled */
if (stream->next_track == false)
return -EPERM;
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
stream->next_track = false;
return retval;
}
static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
struct snd_compr_file *data = f->private_data;
@ -623,6 +712,12 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
retval = snd_compr_get_params(stream, arg);
break;
case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
retval = snd_compr_set_metadata(stream, arg);
break;
case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
retval = snd_compr_get_metadata(stream, arg);
break;
case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
retval = snd_compr_tstamp(stream, arg);
break;
@ -644,6 +739,13 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
case _IOC_NR(SNDRV_COMPRESS_DRAIN):
retval = snd_compr_drain(stream);
break;
case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
retval = snd_compr_partial_drain(stream);
break;
case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
retval = snd_compr_next_track(stream);
break;
}
mutex_unlock(&stream->device->lock);
return retval;

View File

@ -286,12 +286,14 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
loopback_active_notify(dpcm);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
spin_lock(&cable->lock);
cable->pause |= stream;
loopback_timer_stop(dpcm);
spin_unlock(&cable->lock);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
spin_lock(&cable->lock);
dpcm->last_jiffies = jiffies;
cable->pause &= ~stream;
@ -563,7 +565,8 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
static struct snd_pcm_hardware loopback_pcm_hardware =
{
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME),
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),

View File

@ -52,7 +52,6 @@ MODULE_LICENSE("GPL");
int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int time)
{
unsigned long end_time = jiffies + (time * HZ + 999) / 1000;
#ifdef CONFIG_SND_DEBUG
static char *reg_names[VX_REG_MAX] = {
"ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL",
"DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ",
@ -60,7 +59,7 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t
"MIC3", "INTCSR", "CNTRL", "GPIOC",
"LOFREQ", "HIFREQ", "CSUER", "RUER"
};
#endif
do {
if ((snd_vx_inb(chip, reg) & mask) == bit)
return 0;

View File

@ -678,6 +678,7 @@ config SND_LOLA
config SND_LX6464ES
tristate "Digigram LX6464ES"
depends on HAS_IOPORT
select SND_PCM
help
Say Y here to include support for Digigram LX6464ES boards.

View File

@ -1435,7 +1435,7 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream)
spin_lock(&codec->reg_lock);
if (!pvoice->running) {
spin_unlock_irq(&codec->reg_lock);
spin_unlock(&codec->reg_lock);
return 0;
}
outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));

View File

@ -567,8 +567,9 @@ static int ac97_probing_bugs(struct pci_dev *pci)
q = snd_pci_quirk_lookup(pci, atiixp_quirks);
if (q) {
snd_printdd(KERN_INFO "Atiixp quirk for %s. "
"Forcing codec %d\n", q->name, q->value);
snd_printdd(KERN_INFO
"Atiixp quirk for %s. Forcing codec %d\n",
snd_pci_quirk_name(q), q->value);
return q->value;
}
/* this hardware doesn't need workarounds. Probe for codec */

View File

@ -650,6 +650,29 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
snd_dma_pci_data(chip->pci_dev),
0x10000, 0x10000);
switch (VORTEX_PCM_TYPE(pcm)) {
case VORTEX_PCM_ADB:
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps,
VORTEX_IS_QUAD(chip) ? 4 : 2,
0, NULL);
if (err < 0)
return err;
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
snd_pcm_std_chmaps, 2, 0, NULL);
if (err < 0)
return err;
break;
#ifdef CHIP_AU8830
case VORTEX_PCM_A3D:
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps, 1, 0, NULL);
if (err < 0)
return err;
break;
#endif
};
if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);

View File

@ -15,6 +15,9 @@ menuconfig SND_HDA_INTEL
if SND_HDA_INTEL
config SND_HDA_DSP_LOADER
bool
config SND_HDA_PREALLOC_SIZE
int "Pre-allocated buffer size for HD-audio driver"
range 0 32768
@ -86,6 +89,7 @@ config SND_HDA_PATCH_LOADER
config SND_HDA_CODEC_REALTEK
bool "Build Realtek HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include Realtek HD-audio codec support in
snd-hda-intel driver, such as ALC880.
@ -98,6 +102,7 @@ config SND_HDA_CODEC_REALTEK
config SND_HDA_CODEC_ANALOG
bool "Build Analog Device HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include Analog Device HD-audio codec support in
snd-hda-intel driver, such as AD1986A.
@ -110,6 +115,7 @@ config SND_HDA_CODEC_ANALOG
config SND_HDA_CODEC_SIGMATEL
bool "Build IDT/Sigmatel HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include IDT (Sigmatel) HD-audio codec support in
snd-hda-intel driver, such as STAC9200.
@ -122,6 +128,7 @@ config SND_HDA_CODEC_SIGMATEL
config SND_HDA_CODEC_VIA
bool "Build VIA HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include VIA HD-audio codec support in
snd-hda-intel driver, such as VT1708.
@ -147,8 +154,8 @@ config SND_HDA_CODEC_HDMI
config SND_HDA_CODEC_CIRRUS
bool "Build Cirrus Logic codec support"
depends on SND_HDA_INTEL
default y
select SND_HDA_GENERIC
help
Say Y here to include Cirrus Logic codec support in
snd-hda-intel driver, such as CS4206.
@ -161,6 +168,7 @@ config SND_HDA_CODEC_CIRRUS
config SND_HDA_CODEC_CONEXANT
bool "Build Conexant HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include Conexant HD-audio codec support in
snd-hda-intel driver, such as CX20549.
@ -172,8 +180,8 @@ config SND_HDA_CODEC_CONEXANT
config SND_HDA_CODEC_CA0110
bool "Build Creative CA0110-IBG codec support"
depends on SND_HDA_INTEL
default y
select SND_HDA_GENERIC
help
Say Y here to include Creative CA0110-IBG codec support in
snd-hda-intel driver, found on some Creative X-Fi cards.
@ -185,7 +193,6 @@ config SND_HDA_CODEC_CA0110
config SND_HDA_CODEC_CA0132
bool "Build Creative CA0132 codec support"
depends on SND_HDA_INTEL
default y
help
Say Y here to include Creative CA0132 codec support in
@ -196,9 +203,21 @@ config SND_HDA_CODEC_CA0132
snd-hda-codec-ca0132.
This module is automatically loaded at probing.
config SND_HDA_CODEC_CA0132_DSP
bool "Support new DSP code for CA0132 codec"
depends on SND_HDA_CODEC_CA0132 && FW_LOADER
select SND_HDA_DSP_LOADER
help
Say Y here to enable the DSP for Creative CA0132 for extended
features like equalizer or echo cancellation.
Note that this option requires the external firmware file
(ctefx.bin).
config SND_HDA_CODEC_CMEDIA
bool "Build C-Media HD-audio codec support"
default y
select SND_HDA_GENERIC
help
Say Y here to include C-Media HD-audio codec support in
snd-hda-intel driver, such as CMI9880.

409
sound/pci/hda/ca0132_regs.h Normal file
View File

@ -0,0 +1,409 @@
/*
* HD audio interface patch for Creative CA0132 chip.
* CA0132 registers defines.
*
* Copyright (c) 2011, Creative Technology Ltd.
*
* 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
*/
#ifndef __CA0132_REGS_H
#define __CA0312_REGS_H
#define DSP_CHIP_OFFSET 0x100000
#define DSP_DBGCNTL_MODULE_OFFSET 0xE30
#define DSP_DBGCNTL_INST_OFFSET \
(DSP_CHIP_OFFSET + DSP_DBGCNTL_MODULE_OFFSET)
#define DSP_DBGCNTL_EXEC_LOBIT 0x0
#define DSP_DBGCNTL_EXEC_HIBIT 0x3
#define DSP_DBGCNTL_EXEC_MASK 0xF
#define DSP_DBGCNTL_SS_LOBIT 0x4
#define DSP_DBGCNTL_SS_HIBIT 0x7
#define DSP_DBGCNTL_SS_MASK 0xF0
#define DSP_DBGCNTL_STATE_LOBIT 0xA
#define DSP_DBGCNTL_STATE_HIBIT 0xD
#define DSP_DBGCNTL_STATE_MASK 0x3C00
#define XRAM_CHIP_OFFSET 0x0
#define XRAM_XRAM_CHANNEL_COUNT 0xE000
#define XRAM_XRAM_MODULE_OFFSET 0x0
#define XRAM_XRAM_CHAN_INCR 4
#define XRAM_XRAM_INST_OFFSET(_chan) \
(XRAM_CHIP_OFFSET + XRAM_XRAM_MODULE_OFFSET + \
(_chan * XRAM_XRAM_CHAN_INCR))
#define YRAM_CHIP_OFFSET 0x40000
#define YRAM_YRAM_CHANNEL_COUNT 0x8000
#define YRAM_YRAM_MODULE_OFFSET 0x0
#define YRAM_YRAM_CHAN_INCR 4
#define YRAM_YRAM_INST_OFFSET(_chan) \
(YRAM_CHIP_OFFSET + YRAM_YRAM_MODULE_OFFSET + \
(_chan * YRAM_YRAM_CHAN_INCR))
#define UC_CHIP_OFFSET 0x80000
#define UC_UC_CHANNEL_COUNT 0x10000
#define UC_UC_MODULE_OFFSET 0x0
#define UC_UC_CHAN_INCR 4
#define UC_UC_INST_OFFSET(_chan) \
(UC_CHIP_OFFSET + UC_UC_MODULE_OFFSET + \
(_chan * UC_UC_CHAN_INCR))
#define AXRAM_CHIP_OFFSET 0x3C000
#define AXRAM_AXRAM_CHANNEL_COUNT 0x1000
#define AXRAM_AXRAM_MODULE_OFFSET 0x0
#define AXRAM_AXRAM_CHAN_INCR 4
#define AXRAM_AXRAM_INST_OFFSET(_chan) \
(AXRAM_CHIP_OFFSET + AXRAM_AXRAM_MODULE_OFFSET + \
(_chan * AXRAM_AXRAM_CHAN_INCR))
#define AYRAM_CHIP_OFFSET 0x78000
#define AYRAM_AYRAM_CHANNEL_COUNT 0x1000
#define AYRAM_AYRAM_MODULE_OFFSET 0x0
#define AYRAM_AYRAM_CHAN_INCR 4
#define AYRAM_AYRAM_INST_OFFSET(_chan) \
(AYRAM_CHIP_OFFSET + AYRAM_AYRAM_MODULE_OFFSET + \
(_chan * AYRAM_AYRAM_CHAN_INCR))
#define DSPDMAC_CHIP_OFFSET 0x110000
#define DSPDMAC_DMA_CFG_CHANNEL_COUNT 12
#define DSPDMAC_DMACFG_MODULE_OFFSET 0xF00
#define DSPDMAC_DMACFG_CHAN_INCR 0x10
#define DSPDMAC_DMACFG_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DMACFG_MODULE_OFFSET + \
(_chan * DSPDMAC_DMACFG_CHAN_INCR))
#define DSPDMAC_DMACFG_DBADR_LOBIT 0x0
#define DSPDMAC_DMACFG_DBADR_HIBIT 0x10
#define DSPDMAC_DMACFG_DBADR_MASK 0x1FFFF
#define DSPDMAC_DMACFG_LP_LOBIT 0x11
#define DSPDMAC_DMACFG_LP_HIBIT 0x11
#define DSPDMAC_DMACFG_LP_MASK 0x20000
#define DSPDMAC_DMACFG_AINCR_LOBIT 0x12
#define DSPDMAC_DMACFG_AINCR_HIBIT 0x12
#define DSPDMAC_DMACFG_AINCR_MASK 0x40000
#define DSPDMAC_DMACFG_DWR_LOBIT 0x13
#define DSPDMAC_DMACFG_DWR_HIBIT 0x13
#define DSPDMAC_DMACFG_DWR_MASK 0x80000
#define DSPDMAC_DMACFG_AJUMP_LOBIT 0x14
#define DSPDMAC_DMACFG_AJUMP_HIBIT 0x17
#define DSPDMAC_DMACFG_AJUMP_MASK 0xF00000
#define DSPDMAC_DMACFG_AMODE_LOBIT 0x18
#define DSPDMAC_DMACFG_AMODE_HIBIT 0x19
#define DSPDMAC_DMACFG_AMODE_MASK 0x3000000
#define DSPDMAC_DMACFG_LK_LOBIT 0x1A
#define DSPDMAC_DMACFG_LK_HIBIT 0x1A
#define DSPDMAC_DMACFG_LK_MASK 0x4000000
#define DSPDMAC_DMACFG_AICS_LOBIT 0x1B
#define DSPDMAC_DMACFG_AICS_HIBIT 0x1F
#define DSPDMAC_DMACFG_AICS_MASK 0xF8000000
#define DSPDMAC_DMACFG_LP_SINGLE 0
#define DSPDMAC_DMACFG_LP_LOOPING 1
#define DSPDMAC_DMACFG_AINCR_XANDY 0
#define DSPDMAC_DMACFG_AINCR_XORY 1
#define DSPDMAC_DMACFG_DWR_DMA_RD 0
#define DSPDMAC_DMACFG_DWR_DMA_WR 1
#define DSPDMAC_DMACFG_AMODE_LINEAR 0
#define DSPDMAC_DMACFG_AMODE_RSV1 1
#define DSPDMAC_DMACFG_AMODE_WINTLV 2
#define DSPDMAC_DMACFG_AMODE_GINTLV 3
#define DSPDMAC_DSP_ADR_OFS_CHANNEL_COUNT 12
#define DSPDMAC_DSPADROFS_MODULE_OFFSET 0xF04
#define DSPDMAC_DSPADROFS_CHAN_INCR 0x10
#define DSPDMAC_DSPADROFS_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADROFS_MODULE_OFFSET + \
(_chan * DSPDMAC_DSPADROFS_CHAN_INCR))
#define DSPDMAC_DSPADROFS_COFS_LOBIT 0x0
#define DSPDMAC_DSPADROFS_COFS_HIBIT 0xF
#define DSPDMAC_DSPADROFS_COFS_MASK 0xFFFF
#define DSPDMAC_DSPADROFS_BOFS_LOBIT 0x10
#define DSPDMAC_DSPADROFS_BOFS_HIBIT 0x1F
#define DSPDMAC_DSPADROFS_BOFS_MASK 0xFFFF0000
#define DSPDMAC_DSP_ADR_WOFS_CHANNEL_COUNT 12
#define DSPDMAC_DSPADRWOFS_MODULE_OFFSET 0xF04
#define DSPDMAC_DSPADRWOFS_CHAN_INCR 0x10
#define DSPDMAC_DSPADRWOFS_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRWOFS_MODULE_OFFSET + \
(_chan * DSPDMAC_DSPADRWOFS_CHAN_INCR))
#define DSPDMAC_DSPADRWOFS_WCOFS_LOBIT 0x0
#define DSPDMAC_DSPADRWOFS_WCOFS_HIBIT 0xA
#define DSPDMAC_DSPADRWOFS_WCOFS_MASK 0x7FF
#define DSPDMAC_DSPADRWOFS_WCBFR_LOBIT 0xB
#define DSPDMAC_DSPADRWOFS_WCBFR_HIBIT 0xF
#define DSPDMAC_DSPADRWOFS_WCBFR_MASK 0xF800
#define DSPDMAC_DSPADRWOFS_WBOFS_LOBIT 0x10
#define DSPDMAC_DSPADRWOFS_WBOFS_HIBIT 0x1A
#define DSPDMAC_DSPADRWOFS_WBOFS_MASK 0x7FF0000
#define DSPDMAC_DSPADRWOFS_WBBFR_LOBIT 0x1B
#define DSPDMAC_DSPADRWOFS_WBBFR_HIBIT 0x1F
#define DSPDMAC_DSPADRWOFS_WBBFR_MASK 0xF8000000
#define DSPDMAC_DSP_ADR_GOFS_CHANNEL_COUNT 12
#define DSPDMAC_DSPADRGOFS_MODULE_OFFSET 0xF04
#define DSPDMAC_DSPADRGOFS_CHAN_INCR 0x10
#define DSPDMAC_DSPADRGOFS_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRGOFS_MODULE_OFFSET + \
(_chan * DSPDMAC_DSPADRGOFS_CHAN_INCR))
#define DSPDMAC_DSPADRGOFS_GCOFS_LOBIT 0x0
#define DSPDMAC_DSPADRGOFS_GCOFS_HIBIT 0x9
#define DSPDMAC_DSPADRGOFS_GCOFS_MASK 0x3FF
#define DSPDMAC_DSPADRGOFS_GCS_LOBIT 0xA
#define DSPDMAC_DSPADRGOFS_GCS_HIBIT 0xC
#define DSPDMAC_DSPADRGOFS_GCS_MASK 0x1C00
#define DSPDMAC_DSPADRGOFS_GCBFR_LOBIT 0xD
#define DSPDMAC_DSPADRGOFS_GCBFR_HIBIT 0xF
#define DSPDMAC_DSPADRGOFS_GCBFR_MASK 0xE000
#define DSPDMAC_DSPADRGOFS_GBOFS_LOBIT 0x10
#define DSPDMAC_DSPADRGOFS_GBOFS_HIBIT 0x19
#define DSPDMAC_DSPADRGOFS_GBOFS_MASK 0x3FF0000
#define DSPDMAC_DSPADRGOFS_GBS_LOBIT 0x1A
#define DSPDMAC_DSPADRGOFS_GBS_HIBIT 0x1C
#define DSPDMAC_DSPADRGOFS_GBS_MASK 0x1C000000
#define DSPDMAC_DSPADRGOFS_GBBFR_LOBIT 0x1D
#define DSPDMAC_DSPADRGOFS_GBBFR_HIBIT 0x1F
#define DSPDMAC_DSPADRGOFS_GBBFR_MASK 0xE0000000
#define DSPDMAC_XFR_CNT_CHANNEL_COUNT 12
#define DSPDMAC_XFRCNT_MODULE_OFFSET 0xF08
#define DSPDMAC_XFRCNT_CHAN_INCR 0x10
#define DSPDMAC_XFRCNT_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_XFRCNT_MODULE_OFFSET + \
(_chan * DSPDMAC_XFRCNT_CHAN_INCR))
#define DSPDMAC_XFRCNT_CCNT_LOBIT 0x0
#define DSPDMAC_XFRCNT_CCNT_HIBIT 0xF
#define DSPDMAC_XFRCNT_CCNT_MASK 0xFFFF
#define DSPDMAC_XFRCNT_BCNT_LOBIT 0x10
#define DSPDMAC_XFRCNT_BCNT_HIBIT 0x1F
#define DSPDMAC_XFRCNT_BCNT_MASK 0xFFFF0000
#define DSPDMAC_IRQ_CNT_CHANNEL_COUNT 12
#define DSPDMAC_IRQCNT_MODULE_OFFSET 0xF0C
#define DSPDMAC_IRQCNT_CHAN_INCR 0x10
#define DSPDMAC_IRQCNT_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_IRQCNT_MODULE_OFFSET + \
(_chan * DSPDMAC_IRQCNT_CHAN_INCR))
#define DSPDMAC_IRQCNT_CICNT_LOBIT 0x0
#define DSPDMAC_IRQCNT_CICNT_HIBIT 0xF
#define DSPDMAC_IRQCNT_CICNT_MASK 0xFFFF
#define DSPDMAC_IRQCNT_BICNT_LOBIT 0x10
#define DSPDMAC_IRQCNT_BICNT_HIBIT 0x1F
#define DSPDMAC_IRQCNT_BICNT_MASK 0xFFFF0000
#define DSPDMAC_AUD_CHSEL_CHANNEL_COUNT 12
#define DSPDMAC_AUDCHSEL_MODULE_OFFSET 0xFC0
#define DSPDMAC_AUDCHSEL_CHAN_INCR 0x4
#define DSPDMAC_AUDCHSEL_INST_OFFSET(_chan) \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_AUDCHSEL_MODULE_OFFSET + \
(_chan * DSPDMAC_AUDCHSEL_CHAN_INCR))
#define DSPDMAC_AUDCHSEL_ACS_LOBIT 0x0
#define DSPDMAC_AUDCHSEL_ACS_HIBIT 0x1F
#define DSPDMAC_AUDCHSEL_ACS_MASK 0xFFFFFFFF
#define DSPDMAC_CHNLSTART_MODULE_OFFSET 0xFF0
#define DSPDMAC_CHNLSTART_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTART_MODULE_OFFSET)
#define DSPDMAC_CHNLSTART_EN_LOBIT 0x0
#define DSPDMAC_CHNLSTART_EN_HIBIT 0xB
#define DSPDMAC_CHNLSTART_EN_MASK 0xFFF
#define DSPDMAC_CHNLSTART_VAI1_LOBIT 0xC
#define DSPDMAC_CHNLSTART_VAI1_HIBIT 0xF
#define DSPDMAC_CHNLSTART_VAI1_MASK 0xF000
#define DSPDMAC_CHNLSTART_DIS_LOBIT 0x10
#define DSPDMAC_CHNLSTART_DIS_HIBIT 0x1B
#define DSPDMAC_CHNLSTART_DIS_MASK 0xFFF0000
#define DSPDMAC_CHNLSTART_VAI2_LOBIT 0x1C
#define DSPDMAC_CHNLSTART_VAI2_HIBIT 0x1F
#define DSPDMAC_CHNLSTART_VAI2_MASK 0xF0000000
#define DSPDMAC_CHNLSTATUS_MODULE_OFFSET 0xFF4
#define DSPDMAC_CHNLSTATUS_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTATUS_MODULE_OFFSET)
#define DSPDMAC_CHNLSTATUS_ISC_LOBIT 0x0
#define DSPDMAC_CHNLSTATUS_ISC_HIBIT 0xB
#define DSPDMAC_CHNLSTATUS_ISC_MASK 0xFFF
#define DSPDMAC_CHNLSTATUS_AOO_LOBIT 0xC
#define DSPDMAC_CHNLSTATUS_AOO_HIBIT 0xC
#define DSPDMAC_CHNLSTATUS_AOO_MASK 0x1000
#define DSPDMAC_CHNLSTATUS_AOU_LOBIT 0xD
#define DSPDMAC_CHNLSTATUS_AOU_HIBIT 0xD
#define DSPDMAC_CHNLSTATUS_AOU_MASK 0x2000
#define DSPDMAC_CHNLSTATUS_AIO_LOBIT 0xE
#define DSPDMAC_CHNLSTATUS_AIO_HIBIT 0xE
#define DSPDMAC_CHNLSTATUS_AIO_MASK 0x4000
#define DSPDMAC_CHNLSTATUS_AIU_LOBIT 0xF
#define DSPDMAC_CHNLSTATUS_AIU_HIBIT 0xF
#define DSPDMAC_CHNLSTATUS_AIU_MASK 0x8000
#define DSPDMAC_CHNLSTATUS_IEN_LOBIT 0x10
#define DSPDMAC_CHNLSTATUS_IEN_HIBIT 0x1B
#define DSPDMAC_CHNLSTATUS_IEN_MASK 0xFFF0000
#define DSPDMAC_CHNLSTATUS_VAI0_LOBIT 0x1C
#define DSPDMAC_CHNLSTATUS_VAI0_HIBIT 0x1F
#define DSPDMAC_CHNLSTATUS_VAI0_MASK 0xF0000000
#define DSPDMAC_CHNLPROP_MODULE_OFFSET 0xFF8
#define DSPDMAC_CHNLPROP_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLPROP_MODULE_OFFSET)
#define DSPDMAC_CHNLPROP_DCON_LOBIT 0x0
#define DSPDMAC_CHNLPROP_DCON_HIBIT 0xB
#define DSPDMAC_CHNLPROP_DCON_MASK 0xFFF
#define DSPDMAC_CHNLPROP_FFS_LOBIT 0xC
#define DSPDMAC_CHNLPROP_FFS_HIBIT 0xC
#define DSPDMAC_CHNLPROP_FFS_MASK 0x1000
#define DSPDMAC_CHNLPROP_NAJ_LOBIT 0xD
#define DSPDMAC_CHNLPROP_NAJ_HIBIT 0xD
#define DSPDMAC_CHNLPROP_NAJ_MASK 0x2000
#define DSPDMAC_CHNLPROP_ENH_LOBIT 0xE
#define DSPDMAC_CHNLPROP_ENH_HIBIT 0xE
#define DSPDMAC_CHNLPROP_ENH_MASK 0x4000
#define DSPDMAC_CHNLPROP_MSPCE_LOBIT 0x10
#define DSPDMAC_CHNLPROP_MSPCE_HIBIT 0x1B
#define DSPDMAC_CHNLPROP_MSPCE_MASK 0xFFF0000
#define DSPDMAC_CHNLPROP_AC_LOBIT 0x1C
#define DSPDMAC_CHNLPROP_AC_HIBIT 0x1F
#define DSPDMAC_CHNLPROP_AC_MASK 0xF0000000
#define DSPDMAC_ACTIVE_MODULE_OFFSET 0xFFC
#define DSPDMAC_ACTIVE_INST_OFFSET \
(DSPDMAC_CHIP_OFFSET + DSPDMAC_ACTIVE_MODULE_OFFSET)
#define DSPDMAC_ACTIVE_AAR_LOBIT 0x0
#define DSPDMAC_ACTIVE_AAR_HIBIT 0xB
#define DSPDMAC_ACTIVE_AAR_MASK 0xFFF
#define DSPDMAC_ACTIVE_WFR_LOBIT 0xC
#define DSPDMAC_ACTIVE_WFR_HIBIT 0x17
#define DSPDMAC_ACTIVE_WFR_MASK 0xFFF000
#define DSP_AUX_MEM_BASE 0xE000
#define INVALID_CHIP_ADDRESS (~0U)
#define X_SIZE (XRAM_XRAM_CHANNEL_COUNT * XRAM_XRAM_CHAN_INCR)
#define Y_SIZE (YRAM_YRAM_CHANNEL_COUNT * YRAM_YRAM_CHAN_INCR)
#define AX_SIZE (AXRAM_AXRAM_CHANNEL_COUNT * AXRAM_AXRAM_CHAN_INCR)
#define AY_SIZE (AYRAM_AYRAM_CHANNEL_COUNT * AYRAM_AYRAM_CHAN_INCR)
#define UC_SIZE (UC_UC_CHANNEL_COUNT * UC_UC_CHAN_INCR)
#define XEXT_SIZE (X_SIZE + AX_SIZE)
#define YEXT_SIZE (Y_SIZE + AY_SIZE)
#define U64K 0x10000UL
#define X_END (XRAM_CHIP_OFFSET + X_SIZE)
#define X_EXT (XRAM_CHIP_OFFSET + XEXT_SIZE)
#define AX_END (XRAM_CHIP_OFFSET + U64K*4)
#define Y_END (YRAM_CHIP_OFFSET + Y_SIZE)
#define Y_EXT (YRAM_CHIP_OFFSET + YEXT_SIZE)
#define AY_END (YRAM_CHIP_OFFSET + U64K*4)
#define UC_END (UC_CHIP_OFFSET + UC_SIZE)
#define X_RANGE_MAIN(a, s) \
(((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < X_END))
#define X_RANGE_AUX(a, s) \
(((a) >= X_END) && ((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
#define X_RANGE_EXT(a, s) \
(((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < X_EXT))
#define X_RANGE_ALL(a, s) \
(((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
#define Y_RANGE_MAIN(a, s) \
(((a) >= YRAM_CHIP_OFFSET) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < Y_END))
#define Y_RANGE_AUX(a, s) \
(((a) >= Y_END) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
#define Y_RANGE_EXT(a, s) \
(((a) >= YRAM_CHIP_OFFSET) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < Y_EXT))
#define Y_RANGE_ALL(a, s) \
(((a) >= YRAM_CHIP_OFFSET) && \
((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
#define UC_RANGE(a, s) \
(((a) >= UC_CHIP_OFFSET) && \
((a)+((s)-1)*UC_UC_CHAN_INCR < UC_END))
#define X_OFF(a) \
(((a) - XRAM_CHIP_OFFSET) / XRAM_XRAM_CHAN_INCR)
#define AX_OFF(a) \
(((a) % (AXRAM_AXRAM_CHANNEL_COUNT * \
AXRAM_AXRAM_CHAN_INCR)) / AXRAM_AXRAM_CHAN_INCR)
#define Y_OFF(a) \
(((a) - YRAM_CHIP_OFFSET) / YRAM_YRAM_CHAN_INCR)
#define AY_OFF(a) \
(((a) % (AYRAM_AYRAM_CHANNEL_COUNT * \
AYRAM_AYRAM_CHAN_INCR)) / AYRAM_AYRAM_CHAN_INCR)
#define UC_OFF(a) (((a) - UC_CHIP_OFFSET) / UC_UC_CHAN_INCR)
#define X_EXT_MAIN_SIZE(a) (XRAM_XRAM_CHANNEL_COUNT - X_OFF(a))
#define X_EXT_AUX_SIZE(a, s) ((s) - X_EXT_MAIN_SIZE(a))
#define Y_EXT_MAIN_SIZE(a) (YRAM_YRAM_CHANNEL_COUNT - Y_OFF(a))
#define Y_EXT_AUX_SIZE(a, s) ((s) - Y_EXT_MAIN_SIZE(a))
#endif

View File

@ -97,6 +97,28 @@ static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
}
}
/* check whether the given pin has a proper pin I/O capability bit */
static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin,
unsigned int dev)
{
unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
/* some old hardware don't return the proper pincaps */
if (!pincap)
return true;
switch (dev) {
case AC_JACK_LINE_OUT:
case AC_JACK_SPEAKER:
case AC_JACK_HP_OUT:
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
return !!(pincap & AC_PINCAP_OUT);
default:
return !!(pincap & AC_PINCAP_IN);
}
}
/*
* Parse all pin widgets and store the useful pin nids to cfg
*
@ -126,6 +148,9 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)];
int i;
if (!snd_hda_get_int_hint(codec, "parser_flags", &i))
cond_flags = i;
memset(cfg, 0, sizeof(*cfg));
memset(line_out, 0, sizeof(line_out));
@ -156,10 +181,14 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
/* workaround for buggy BIOS setups */
if (dev == AC_JACK_LINE_OUT) {
if (conn == AC_JACK_PORT_FIXED)
if (conn == AC_JACK_PORT_FIXED ||
conn == AC_JACK_PORT_BOTH)
dev = AC_JACK_SPEAKER;
}
if (!check_pincap_validity(codec, nid, dev))
continue;
switch (dev) {
case AC_JACK_LINE_OUT:
seq = get_defcfg_sequence(def_conf);
@ -363,7 +392,7 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
{
unsigned int def_conf;
static const char * const mic_names[] = {
"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
"Internal Mic", "Dock Mic", "Mic", "Rear Mic", "Front Mic"
};
int attr;
@ -394,6 +423,8 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec,
return "SPDIF In";
case AC_JACK_DIG_OTHER_IN:
return "Digital In";
case AC_JACK_HP_OUT:
return "Headphone Mic";
default:
return "Misc";
}
@ -552,6 +583,9 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
return 1;
}
#define is_hdmi_cfg(conf) \
(get_defcfg_location(conf) == AC_JACK_LOC_HDMI)
/**
* snd_hda_get_pin_label - Get a label for the given I/O pin
*
@ -572,6 +606,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
const char *name = NULL;
int i;
bool hdmi;
if (indexp)
*indexp = 0;
@ -590,16 +625,18 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
label, maxlen, indexp);
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
name = "HDMI";
else
name = "SPDIF";
if (cfg && indexp) {
i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
cfg->dig_outs);
if (i >= 0)
*indexp = i;
}
hdmi = is_hdmi_cfg(def_conf);
name = hdmi ? "HDMI" : "SPDIF";
if (cfg && indexp)
for (i = 0; i < cfg->dig_outs; i++) {
hda_nid_t pin = cfg->dig_out_pins[i];
unsigned int c;
if (pin == nid)
break;
c = snd_hda_codec_get_pincfg(codec, pin);
if (hdmi == is_hdmi_cfg(c))
(*indexp)++;
}
break;
default:
if (cfg) {
@ -622,28 +659,27 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
const struct hda_verb *list)
int snd_hda_add_verbs(struct hda_codec *codec,
const struct hda_verb *list)
{
const struct hda_verb **v;
v = snd_array_new(&spec->verbs);
v = snd_array_new(&codec->verbs);
if (!v)
return -ENOMEM;
*v = list;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
EXPORT_SYMBOL_HDA(snd_hda_add_verbs);
void snd_hda_gen_apply_verbs(struct hda_codec *codec)
void snd_hda_apply_verbs(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
int i;
for (i = 0; i < spec->verbs.used; i++) {
struct hda_verb **v = snd_array_elem(&spec->verbs, i);
for (i = 0; i < codec->verbs.used; i++) {
struct hda_verb **v = snd_array_elem(&codec->verbs, i);
snd_hda_sequence_write(codec, *v);
}
}
EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
EXPORT_SYMBOL_HDA(snd_hda_apply_verbs);
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg)
@ -653,20 +689,22 @@ void snd_hda_apply_pincfgs(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
void snd_hda_apply_fixup(struct hda_codec *codec, int action)
static void set_pin_targets(struct hda_codec *codec,
const struct hda_pintbl *cfg)
{
struct hda_gen_spec *spec = codec->spec;
int id = spec->fixup_id;
#ifdef CONFIG_SND_DEBUG_VERBOSE
const char *modelname = spec->fixup_name;
#endif
int depth = 0;
for (; cfg->nid; cfg++)
snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val);
}
if (!spec->fixup_list)
return;
static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
{
const char *modelname = codec->fixup_name;
while (id >= 0) {
const struct hda_fixup *fix = spec->fixup_list + id;
const struct hda_fixup *fix = codec->fixup_list + id;
if (fix->chained_before)
apply_fixup(codec, fix->chain_id, action, depth + 1);
switch (fix->type) {
case HDA_FIXUP_PINS:
@ -683,7 +721,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
snd_printdd(KERN_INFO SFX
"%s: Apply fix-verbs for %s\n",
codec->chip_name, modelname);
snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
snd_hda_add_verbs(codec, fix->v.verbs);
break;
case HDA_FIXUP_FUNC:
if (!fix->v.func)
@ -693,19 +731,33 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
codec->chip_name, modelname);
fix->v.func(codec, fix, action);
break;
case HDA_FIXUP_PINCTLS:
if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins)
break;
snd_printdd(KERN_INFO SFX
"%s: Apply pinctl for %s\n",
codec->chip_name, modelname);
set_pin_targets(codec, fix->v.pins);
break;
default:
snd_printk(KERN_ERR SFX
"%s: Invalid fixup type %d\n",
codec->chip_name, fix->type);
break;
}
if (!fix->chained)
if (!fix->chained || fix->chained_before)
break;
if (++depth > 10)
break;
id = fix->chain_id;
}
}
void snd_hda_apply_fixup(struct hda_codec *codec, int action)
{
if (codec->fixup_list)
apply_fixup(codec, codec->fixup_id, action, 0);
}
EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
void snd_hda_pick_fixup(struct hda_codec *codec,
@ -713,15 +765,14 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
const struct snd_pci_quirk *quirk,
const struct hda_fixup *fixlist)
{
struct hda_gen_spec *spec = codec->spec;
const struct snd_pci_quirk *q;
int id = -1;
const char *name = NULL;
/* when model=nofixup is given, don't pick up any fixups */
if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
spec->fixup_list = NULL;
spec->fixup_id = -1;
codec->fixup_list = NULL;
codec->fixup_id = -1;
return;
}
@ -759,10 +810,10 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
}
}
spec->fixup_id = id;
codec->fixup_id = id;
if (id >= 0) {
spec->fixup_list = fixlist;
spec->fixup_name = name;
codec->fixup_list = fixlist;
codec->fixup_name = name;
}
}
EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);

View File

@ -51,8 +51,9 @@ enum {
INPUT_PIN_ATTR_INT, /* internal mic/line-in */
INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
INPUT_PIN_ATTR_LAST = INPUT_PIN_ATTR_FRONT,
};
int snd_hda_get_input_pin_attr(unsigned int def_conf);
@ -89,82 +90,4 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
/*
*/
struct hda_gen_spec {
/* fix-up list */
int fixup_id;
const struct hda_fixup *fixup_list;
const char *fixup_name;
/* additional init verbs */
struct snd_array verbs;
};
/*
* Fix-up pin default configurations and add default verbs
*/
struct hda_pintbl {
hda_nid_t nid;
u32 val;
};
struct hda_model_fixup {
const int id;
const char *name;
};
struct hda_fixup {
int type;
bool chained;
int chain_id;
union {
const struct hda_pintbl *pins;
const struct hda_verb *verbs;
void (*func)(struct hda_codec *codec,
const struct hda_fixup *fix,
int action);
} v;
};
/* fixup types */
enum {
HDA_FIXUP_INVALID,
HDA_FIXUP_PINS,
HDA_FIXUP_VERBS,
HDA_FIXUP_FUNC,
};
/* fixup action definitions */
enum {
HDA_FIXUP_ACT_PRE_PROBE,
HDA_FIXUP_ACT_PROBE,
HDA_FIXUP_ACT_INIT,
HDA_FIXUP_ACT_BUILD,
};
int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
const struct hda_verb *list);
void snd_hda_gen_apply_verbs(struct hda_codec *codec);
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg);
void snd_hda_apply_fixup(struct hda_codec *codec, int action);
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
const struct snd_pci_quirk *quirk,
const struct hda_fixup *fixlist);
static inline void snd_hda_gen_init(struct hda_gen_spec *spec)
{
snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
}
static inline void snd_hda_gen_free(struct hda_gen_spec *spec)
{
snd_array_free(&spec->verbs);
}
#endif /* __SOUND_HDA_AUTO_PARSER_H */

File diff suppressed because it is too large Load Diff

View File

@ -551,9 +551,6 @@ enum {
AC_JACK_PORT_BOTH,
};
/* max. connections to a widget */
#define HDA_MAX_CONNECTIONS 32
/* max. codec address */
#define HDA_MAX_CODEC_ADDRESS 0x0f
@ -618,6 +615,17 @@ struct hda_bus_ops {
/* notify power-up/down from codec to controller */
void (*pm_notify)(struct hda_bus *bus, bool power_up);
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
/* prepare DSP transfer */
int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format,
unsigned int byte_size,
struct snd_dma_buffer *bufp);
/* start/stop DSP transfer */
void (*load_dsp_trigger)(struct hda_bus *bus, bool start);
/* clean up DSP transfer */
void (*load_dsp_cleanup)(struct hda_bus *bus,
struct snd_dma_buffer *dmab);
#endif
};
/* template to pass to the bus constructor */
@ -671,6 +679,8 @@ struct hda_bus {
unsigned int response_reset:1; /* controller was reset */
unsigned int in_reset:1; /* during reset operation */
unsigned int power_keep_link_on:1; /* don't power off HDA link */
int primary_dig_out_type; /* primary digital out PCM type */
};
/*
@ -719,9 +729,10 @@ struct hda_codec_ops {
/* record for amp information cache */
struct hda_cache_head {
u32 key; /* hash key */
u32 key:31; /* hash key */
u32 dirty:1;
u16 val; /* assigned value */
u16 next; /* next link; -1 = terminal */
u16 next;
};
struct hda_amp_info {
@ -830,20 +841,20 @@ struct hda_codec {
struct hda_cache_rec amp_cache; /* cache for amp access */
struct hda_cache_rec cmd_cache; /* cache for other commands */
struct snd_array conn_lists; /* connection-list array */
struct list_head conn_list; /* linked-list of connection-list */
struct mutex spdif_mutex;
struct mutex control_mutex;
struct mutex hash_mutex;
struct snd_array spdif_out;
unsigned int spdif_in_enable; /* SPDIF input enable? */
int primary_dig_out_type; /* primary digital out PCM type */
const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
struct snd_array init_pins; /* initial (BIOS) pin configurations */
struct snd_array driver_pins; /* pin configs set by codec parser */
struct snd_array cvt_setups; /* audio convert setups */
#ifdef CONFIG_SND_HDA_HWDEP
struct mutex user_mutex;
struct snd_hwdep *hwdep; /* assigned hwdep device */
struct snd_array init_verbs; /* additional init verbs */
struct snd_array hints; /* additional hints */
@ -865,8 +876,11 @@ struct hda_codec {
unsigned int pins_shutup:1; /* pins are shut up */
unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
unsigned int no_jack_detect:1; /* Machine has no jack-detection */
unsigned int inv_eapd:1; /* broken h/w: inverted EAPD control */
unsigned int inv_jack_detect:1; /* broken h/w: inverted detection bit */
unsigned int pcm_format_first:1; /* PCM format must be set first */
unsigned int epss:1; /* supporting EPSS? */
unsigned int cached_write:1; /* write only to caches */
#ifdef CONFIG_PM
unsigned int power_on :1; /* current (global) power-state */
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
@ -881,6 +895,10 @@ struct hda_codec {
spinlock_t power_lock;
#endif
/* filter the requested power state per nid */
unsigned int (*power_filter)(struct hda_codec *codec, hda_nid_t nid,
unsigned int power_state);
/* codec-specific additional proc output */
void (*proc_widget_hook)(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid);
@ -894,6 +912,14 @@ struct hda_codec {
/* jack detection */
struct snd_array jacks;
#endif
/* fix-up list */
int fixup_id;
const struct hda_fixup *fixup_list;
const char *fixup_name;
/* additional init verbs */
struct snd_array verbs;
};
/* direction */
@ -910,6 +936,7 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
struct hda_codec **codecp);
int snd_hda_codec_configure(struct hda_codec *codec);
int snd_hda_codec_update_widgets(struct hda_codec *codec);
/*
* low level functions
@ -930,8 +957,11 @@ snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_get_connections(codec, nid, NULL, 0);
}
int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
const hda_nid_t **listp);
int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
const hda_nid_t *list);
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
@ -952,7 +982,6 @@ void snd_hda_sequence_write(struct hda_codec *codec,
int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
/* cached write */
#ifdef CONFIG_PM
int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm);
void snd_hda_sequence_write_cache(struct hda_codec *codec,
@ -960,17 +989,14 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
int direct, unsigned int verb, unsigned int parm);
void snd_hda_codec_resume_cache(struct hda_codec *codec);
#else
#define snd_hda_codec_write_cache snd_hda_codec_write
#define snd_hda_codec_update_cache snd_hda_codec_write
#define snd_hda_sequence_write_cache snd_hda_sequence_write
#endif
/* both for cmd & amp caches */
void snd_hda_codec_flush_cache(struct hda_codec *codec);
/* the struct for codec->pin_configs */
struct hda_pincfg {
hda_nid_t nid;
unsigned char ctrl; /* current pin control value */
unsigned char pad; /* reserved */
unsigned char ctrl; /* original pin control value */
unsigned char target; /* target pin control value */
unsigned int cfg; /* default configuration */
};
@ -1036,8 +1062,7 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[];
void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
void snd_hda_bus_reboot_notify(struct hda_bus *bus);
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state,
bool eapd_workaround);
unsigned int power_state);
int snd_hda_lock_devices(struct hda_bus *bus);
void snd_hda_unlock_devices(struct hda_bus *bus);
@ -1136,6 +1161,40 @@ static inline void snd_hda_power_sync(struct hda_codec *codec)
int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
static inline int
snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
unsigned int size,
struct snd_dma_buffer *bufp)
{
return codec->bus->ops.load_dsp_prepare(codec->bus, format, size, bufp);
}
static inline void
snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start)
{
return codec->bus->ops.load_dsp_trigger(codec->bus, start);
}
static inline void
snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
struct snd_dma_buffer *dmab)
{
return codec->bus->ops.load_dsp_cleanup(codec->bus, dmab);
}
#else
static inline int
snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format,
unsigned int size,
struct snd_dma_buffer *bufp)
{
return -ENOSYS;
}
static inline void
snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) {}
static inline void
snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
struct snd_dma_buffer *dmab) {}
#endif
/*
* Codec modularization
*/

View File

@ -246,8 +246,8 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a,
/*
* Be careful, ELD buf could be totally rubbish!
*/
static int hdmi_update_eld(struct hdmi_eld *e,
const unsigned char *buf, int size)
int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e,
const unsigned char *buf, int size)
{
int mnl;
int i;
@ -260,7 +260,6 @@ static int hdmi_update_eld(struct hdmi_eld *e,
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);
@ -305,7 +304,6 @@ static int hdmi_update_eld(struct hdmi_eld *e,
if (!e->spk_alloc)
e->spk_alloc = 0xffff;
e->eld_valid = true;
return 0;
out_fail:
@ -318,17 +316,16 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
AC_DIPSIZE_ELD_BUF);
}
int snd_hdmi_get_eld(struct hdmi_eld *eld,
struct hda_codec *codec, hda_nid_t nid)
int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
unsigned char *buf, int *eld_size)
{
int i;
int ret;
int size;
unsigned char *buf;
/*
* ELD size is initialized to zero in caller function. If no errors and
* ELD is valid, actual eld_size is assigned in hdmi_update_eld()
* ELD is valid, actual eld_size is assigned.
*/
size = snd_hdmi_get_eld_size(codec, nid);
@ -343,8 +340,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
}
/* set ELD buffer */
buf = eld->eld_buffer;
for (i = 0; i < size; i++) {
unsigned int val = hdmi_get_eld_data(codec, nid, i);
/*
@ -372,8 +367,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
buf[i] = val;
}
ret = hdmi_update_eld(eld, buf, size);
*eld_size = size;
error:
return ret;
}
@ -438,7 +432,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
buf[j] = '\0'; /* necessary when j == 0 */
}
void snd_hdmi_show_eld(struct hdmi_eld *e)
void snd_hdmi_show_eld(struct parsed_hdmi_eld *e)
{
int i;
@ -487,10 +481,11 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a,
static void hdmi_print_eld_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdmi_eld *e = entry->private_data;
struct hdmi_eld *eld = entry->private_data;
struct parsed_hdmi_eld *e = &eld->info;
char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
int i;
static char *eld_versoin_names[32] = {
static char *eld_version_names[32] = {
"reserved",
"reserved",
"CEA-861D or below",
@ -505,15 +500,18 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
[4 ... 7] = "reserved"
};
snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present);
snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
if (!e->eld_valid)
mutex_lock(&eld->lock);
snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
if (!eld->eld_valid) {
mutex_unlock(&eld->lock);
return;
}
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]);
eld_version_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);
@ -530,18 +528,21 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
for (i = 0; i < e->sad_count; i++)
hdmi_print_sad_info(i, e->sad + i, buffer);
mutex_unlock(&eld->lock);
}
static void hdmi_write_eld_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdmi_eld *e = entry->private_data;
struct hdmi_eld *eld = entry->private_data;
struct parsed_hdmi_eld *e = &eld->info;
char line[64];
char name[64];
char *sname;
long long val;
unsigned int n;
mutex_lock(&eld->lock);
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%s %llx", name, &val) != 2)
continue;
@ -551,9 +552,9 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
* eld_version edid_version
*/
if (!strcmp(name, "monitor_present"))
e->monitor_present = val;
eld->monitor_present = val;
else if (!strcmp(name, "eld_valid"))
e->eld_valid = val;
eld->eld_valid = val;
else if (!strcmp(name, "connection_type"))
e->conn_type = val;
else if (!strcmp(name, "port_id"))
@ -593,6 +594,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
e->sad_count = n + 1;
}
}
mutex_unlock(&eld->lock);
}
@ -627,7 +629,7 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
#endif /* CONFIG_PROC_FS */
/* update PCM info based on ELD */
void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
struct hda_pcm_stream *hinfo)
{
u32 rates;
@ -644,8 +646,8 @@ void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
formats = SNDRV_PCM_FMTBIT_S16_LE;
maxbps = 16;
channels_max = 2;
for (i = 0; i < eld->sad_count; i++) {
struct cea_sad *a = &eld->sad[i];
for (i = 0; i < e->sad_count; i++) {
struct cea_sad *a = &e->sad[i];
rates |= a->rates;
if (a->channels > channels_max)
channels_max = a->channels;

File diff suppressed because it is too large Load Diff

303
sound/pci/hda/hda_generic.h Normal file
View File

@ -0,0 +1,303 @@
/*
* Generic BIOS auto-parser helper functions for HD-audio
*
* Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
*
* 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.
*/
#ifndef __SOUND_HDA_GENERIC_H
#define __SOUND_HDA_GENERIC_H
/* unsol event tags */
enum {
HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT,
HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT
};
/* table entry for multi-io paths */
struct hda_multi_io {
hda_nid_t pin; /* multi-io widget pin NID */
hda_nid_t dac; /* DAC to be connected */
unsigned int ctl_in; /* cached input-pin control value */
};
/* Widget connection path
*
* For output, stored in the order of DAC -> ... -> pin,
* for input, pin -> ... -> ADC.
*
* idx[i] contains the source index number to select on of the widget path[i];
* e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget
* multi[] indicates whether it's a selector widget with multi-connectors
* (i.e. the connection selection is mandatory)
* vol_ctl and mute_ctl contains the NIDs for the assigned mixers
*/
#define MAX_NID_PATH_DEPTH 10
enum {
NID_PATH_VOL_CTL,
NID_PATH_MUTE_CTL,
NID_PATH_BOOST_CTL,
NID_PATH_NUM_CTLS
};
struct nid_path {
int depth;
hda_nid_t path[MAX_NID_PATH_DEPTH];
unsigned char idx[MAX_NID_PATH_DEPTH];
unsigned char multi[MAX_NID_PATH_DEPTH];
unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
bool active;
};
/* mic/line-in auto switching entry */
#define MAX_AUTO_MIC_PINS 3
struct automic_entry {
hda_nid_t pin; /* pin */
int idx; /* imux index, -1 = invalid */
unsigned int attr; /* pin attribute (INPUT_PIN_ATTR_*) */
};
/* active stream id */
enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };
/* PCM hook action */
enum {
HDA_GEN_PCM_ACT_OPEN,
HDA_GEN_PCM_ACT_PREPARE,
HDA_GEN_PCM_ACT_CLEANUP,
HDA_GEN_PCM_ACT_CLOSE,
};
struct hda_gen_spec {
char stream_name_analog[32]; /* analog PCM stream */
const struct hda_pcm_stream *stream_analog_playback;
const struct hda_pcm_stream *stream_analog_capture;
char stream_name_alt_analog[32]; /* alternative analog PCM stream */
const struct hda_pcm_stream *stream_analog_alt_playback;
const struct hda_pcm_stream *stream_analog_alt_capture;
char stream_name_digital[32]; /* digital PCM stream */
const struct hda_pcm_stream *stream_digital_playback;
const struct hda_pcm_stream *stream_digital_capture;
/* PCM */
unsigned int active_streams;
struct mutex pcm_mutex;
/* playback */
struct hda_multi_out multiout; /* playback set-up
* max_channels, dacs must be set
* dig_out_nid and hp_nid are optional
*/
hda_nid_t alt_dac_nid;
hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
int dig_out_type;
/* capture */
unsigned int num_adc_nids;
hda_nid_t adc_nids[AUTO_CFG_MAX_INS];
hda_nid_t dig_in_nid; /* digital-in NID; optional */
hda_nid_t mixer_nid; /* analog-mixer NID */
hda_nid_t mixer_merge_nid; /* aamix merge-point NID (optional) */
const char *input_labels[HDA_MAX_NUM_INPUTS];
int input_label_idxs[HDA_MAX_NUM_INPUTS];
/* capture setup for dynamic dual-adc switch */
hda_nid_t cur_adc;
unsigned int cur_adc_stream_tag;
unsigned int cur_adc_format;
/* capture source */
struct hda_input_mux input_mux;
unsigned int cur_mux[3];
/* channel model */
/* min_channel_count contains the minimum channel count for primary
* outputs. When multi_ios is set, the channels can be configured
* between min_channel_count and (min_channel_count + multi_ios * 2).
*
* ext_channel_count contains the current channel count of the primary
* out. This varies in the range above.
*
* Meanwhile, const_channel_count is the channel count for all outputs
* including headphone and speakers. It's a constant value, and the
* PCM is set up as max(ext_channel_count, const_channel_count).
*/
int min_channel_count; /* min. channel count for primary out */
int ext_channel_count; /* current channel count for primary */
int const_channel_count; /* channel count for all */
/* PCM information */
struct hda_pcm pcm_rec[3]; /* used in build_pcms() */
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct snd_array kctls;
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
hda_nid_t shared_mic_vref_pin;
/* DAC/ADC lists */
int num_all_dacs;
hda_nid_t all_dacs[16];
int num_all_adcs;
hda_nid_t all_adcs[AUTO_CFG_MAX_INS];
/* path list */
struct snd_array paths;
/* path indices */
int out_paths[AUTO_CFG_MAX_OUTS];
int hp_paths[AUTO_CFG_MAX_OUTS];
int speaker_paths[AUTO_CFG_MAX_OUTS];
int aamix_out_paths[3];
int digout_paths[AUTO_CFG_MAX_OUTS];
int input_paths[HDA_MAX_NUM_INPUTS][AUTO_CFG_MAX_INS];
int loopback_paths[HDA_MAX_NUM_INPUTS];
int loopback_merge_path;
int digin_path;
/* auto-mic stuff */
int am_num_entries;
struct automic_entry am_entry[MAX_AUTO_MIC_PINS];
/* for pin sensing */
/* current status; set in hda_geneic.c */
unsigned int hp_jack_present:1;
unsigned int line_jack_present:1;
unsigned int speaker_muted:1; /* current status of speaker mute */
unsigned int line_out_muted:1; /* current status of LO mute */
/* internal states of automute / autoswitch behavior */
unsigned int auto_mic:1;
unsigned int automute_speaker:1; /* automute speaker outputs */
unsigned int automute_lo:1; /* automute LO outputs */
/* capabilities detected by parser */
unsigned int detect_hp:1; /* Headphone detection enabled */
unsigned int detect_lo:1; /* Line-out detection enabled */
unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
unsigned int automute_lo_possible:1; /* there are line outs and HP */
/* additional parameters set by codec drivers */
unsigned int master_mute:1; /* master mute over all */
unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
/* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
unsigned int suppress_auto_mic:1; /* suppress input jack auto switch */
/* other parse behavior flags */
unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
unsigned int own_eapd_ctl:1; /* set EAPD by own function */
unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
unsigned int indep_hp:1; /* independent HP supported */
unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
unsigned int add_out_jack_modes:1; /* add output jack mode enum ctls */
unsigned int add_in_jack_modes:1; /* add input jack mode enum ctls */
unsigned int power_down_unused:1; /* power down unused widgets */
/* other internal flags */
unsigned int no_analog:1; /* digital I/O only */
unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
unsigned int indep_hp_enabled:1; /* independent HP enabled */
unsigned int have_aamix_ctl:1;
/* loopback mixing mode */
bool aamix_mode;
/* for virtual master */
hda_nid_t vmaster_nid;
unsigned int vmaster_tlv[4];
struct hda_vmaster_mute_hook vmaster_mute;
struct hda_loopback_check loopback;
struct snd_array loopback_list;
/* multi-io */
int multi_ios;
struct hda_multi_io multi_io[4];
/* hooks */
void (*init_hook)(struct hda_codec *codec);
void (*automute_hook)(struct hda_codec *codec);
void (*cap_sync_hook)(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol);
/* PCM hooks */
void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream,
int action);
void (*pcm_capture_hook)(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream,
int action);
/* automute / autoswitch hooks */
void (*hp_automute_hook)(struct hda_codec *codec,
struct hda_jack_tbl *tbl);
void (*line_automute_hook)(struct hda_codec *codec,
struct hda_jack_tbl *tbl);
void (*mic_autoswitch_hook)(struct hda_codec *codec,
struct hda_jack_tbl *tbl);
};
int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
void snd_hda_gen_spec_free(struct hda_gen_spec *spec);
int snd_hda_gen_init(struct hda_codec *codec);
void snd_hda_gen_free(struct hda_codec *codec);
struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
hda_nid_t from_nid, hda_nid_t to_nid);
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
hda_nid_t to_nid, int anchor_nid,
struct nid_path *path);
struct nid_path *
snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
hda_nid_t to_nid, int anchor_nid);
void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
bool enable, bool add_aamix);
struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
const struct snd_kcontrol_new *temp);
int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
struct auto_pin_cfg *cfg);
int snd_hda_gen_build_controls(struct hda_codec *codec);
int snd_hda_gen_build_pcms(struct hda_codec *codec);
/* standard jack event callbacks */
void snd_hda_gen_hp_automute(struct hda_codec *codec,
struct hda_jack_tbl *jack);
void snd_hda_gen_line_automute(struct hda_codec *codec,
struct hda_jack_tbl *jack);
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
struct hda_jack_tbl *jack);
void snd_hda_gen_update_outputs(struct hda_codec *codec);
#ifdef CONFIG_PM
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
#endif
#endif /* __SOUND_HDA_GENERIC_H */

View File

@ -148,6 +148,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
#endif
mutex_init(&codec->user_mutex);
snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32);
snd_array_init(&codec->hints, sizeof(struct hda_hint), 32);
snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16);
@ -346,12 +347,14 @@ static ssize_t init_verbs_show(struct device *dev,
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
struct hda_codec *codec = hwdep->private_data;
int i, len = 0;
mutex_lock(&codec->user_mutex);
for (i = 0; i < codec->init_verbs.used; i++) {
struct hda_verb *v = snd_array_elem(&codec->init_verbs, i);
len += snprintf(buf + len, PAGE_SIZE - len,
"0x%02x 0x%03x 0x%04x\n",
v->nid, v->verb, v->param);
}
mutex_unlock(&codec->user_mutex);
return len;
}
@ -364,12 +367,16 @@ static int parse_init_verbs(struct hda_codec *codec, const char *buf)
return -EINVAL;
if (!nid || !verb)
return -EINVAL;
mutex_lock(&codec->user_mutex);
v = snd_array_new(&codec->init_verbs);
if (!v)
if (!v) {
mutex_unlock(&codec->user_mutex);
return -ENOMEM;
}
v->nid = nid;
v->verb = verb;
v->param = param;
mutex_unlock(&codec->user_mutex);
return 0;
}
@ -392,11 +399,13 @@ static ssize_t hints_show(struct device *dev,
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
struct hda_codec *codec = hwdep->private_data;
int i, len = 0;
mutex_lock(&codec->user_mutex);
for (i = 0; i < codec->hints.used; i++) {
struct hda_hint *hint = snd_array_elem(&codec->hints, i);
len += snprintf(buf + len, PAGE_SIZE - len,
"%s = %s\n", hint->key, hint->val);
}
mutex_unlock(&codec->user_mutex);
return len;
}
@ -431,6 +440,7 @@ static int parse_hints(struct hda_codec *codec, const char *buf)
{
char *key, *val;
struct hda_hint *hint;
int err = 0;
buf = skip_spaces(buf);
if (!*buf || *buf == '#' || *buf == '\n')
@ -450,26 +460,31 @@ static int parse_hints(struct hda_codec *codec, const char *buf)
val = skip_spaces(val);
remove_trail_spaces(key);
remove_trail_spaces(val);
mutex_lock(&codec->user_mutex);
hint = get_hint(codec, key);
if (hint) {
/* replace */
kfree(hint->key);
hint->key = key;
hint->val = val;
return 0;
goto unlock;
}
/* allocate a new hint entry */
if (codec->hints.used >= MAX_HINTS)
hint = NULL;
else
hint = snd_array_new(&codec->hints);
if (!hint) {
kfree(key);
return -ENOMEM;
if (hint) {
hint->key = key;
hint->val = val;
} else {
err = -ENOMEM;
}
hint->key = key;
hint->val = val;
return 0;
unlock:
mutex_unlock(&codec->user_mutex);
if (err)
kfree(key);
return err;
}
static ssize_t hints_store(struct device *dev,
@ -489,11 +504,13 @@ static ssize_t pin_configs_show(struct hda_codec *codec,
char *buf)
{
int i, len = 0;
mutex_lock(&codec->user_mutex);
for (i = 0; i < list->used; i++) {
struct hda_pincfg *pin = snd_array_elem(list, i);
len += sprintf(buf + len, "0x%02x 0x%08x\n",
pin->nid, pin->cfg);
}
mutex_unlock(&codec->user_mutex);
return len;
}
@ -528,13 +545,16 @@ static ssize_t driver_pin_configs_show(struct device *dev,
static int parse_user_pin_configs(struct hda_codec *codec, const char *buf)
{
int nid, cfg;
int nid, cfg, err;
if (sscanf(buf, "%i %i", &nid, &cfg) != 2)
return -EINVAL;
if (!nid)
return -EINVAL;
return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
mutex_lock(&codec->user_mutex);
err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg);
mutex_unlock(&codec->user_mutex);
return err;
}
static ssize_t user_pin_configs_store(struct device *dev,
@ -600,19 +620,50 @@ EXPORT_SYMBOL_HDA(snd_hda_get_hint);
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
const char *p = snd_hda_get_hint(codec, key);
const char *p;
int ret;
mutex_lock(&codec->user_mutex);
p = snd_hda_get_hint(codec, key);
if (!p || !*p)
return -ENOENT;
switch (toupper(*p)) {
case 'T': /* true */
case 'Y': /* yes */
case '1':
return 1;
ret = -ENOENT;
else {
switch (toupper(*p)) {
case 'T': /* true */
case 'Y': /* yes */
case '1':
ret = 1;
break;
default:
ret = 0;
break;
}
}
return 0;
mutex_unlock(&codec->user_mutex);
return ret;
}
EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
const char *p;
unsigned long val;
int ret;
mutex_lock(&codec->user_mutex);
p = snd_hda_get_hint(codec, key);
if (!p)
ret = -ENOENT;
else if (strict_strtoul(p, 0, &val))
ret = -EINVAL;
else {
*valp = val;
ret = 0;
}
mutex_unlock(&codec->user_mutex);
return ret;
}
EXPORT_SYMBOL_HDA(snd_hda_get_int_hint);
#endif /* CONFIG_SND_HDA_RECONFIG */
#ifdef CONFIG_SND_HDA_PATCH_LOADER

View File

@ -134,8 +134,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
* this may give more power-saving, but will take longer time to
* wake up.
*/
static bool power_save_controller = 1;
module_param(power_save_controller, bool, 0644);
static int power_save_controller = -1;
module_param(power_save_controller, bint, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#endif /* CONFIG_PM */
@ -811,7 +811,7 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
{
struct azx *chip = bus->private_data;
unsigned int addr = azx_command_addr(val);
unsigned int wp;
unsigned int wp, rp;
spin_lock_irq(&chip->reg_lock);
@ -820,11 +820,18 @@ static int azx_corb_send_cmd(struct hda_bus *bus, u32 val)
if (wp == 0xffff) {
/* something wrong, controller likely turned to D3 */
spin_unlock_irq(&chip->reg_lock);
return -1;
return -EIO;
}
wp++;
wp %= ICH6_MAX_CORB_ENTRIES;
rp = azx_readw(chip, CORBRP);
if (wp == rp) {
/* oops, it's full */
spin_unlock_irq(&chip->reg_lock);
return -EAGAIN;
}
chip->rirb.cmds[addr]++;
chip->corb.buf[wp] = cpu_to_le32(val);
azx_writel(chip, CORBWP, wp);
@ -1078,6 +1085,15 @@ static unsigned int azx_get_response(struct hda_bus *bus,
static void azx_power_notify(struct hda_bus *bus, bool power_up);
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
unsigned int byte_size,
struct snd_dma_buffer *bufp);
static void azx_load_dsp_trigger(struct hda_bus *bus, bool start);
static void azx_load_dsp_cleanup(struct hda_bus *bus,
struct snd_dma_buffer *dmab);
#endif
/* reset codec link */
static int azx_reset(struct azx *chip, int full_reset)
{
@ -1401,7 +1417,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
* set up a BDL entry
*/
static int setup_bdle(struct azx *chip,
struct snd_pcm_substream *substream,
struct snd_dma_buffer *dmab,
struct azx_dev *azx_dev, u32 **bdlp,
int ofs, int size, int with_ioc)
{
@ -1414,12 +1430,12 @@ static int setup_bdle(struct azx *chip,
if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
return -EINVAL;
addr = snd_pcm_sgbuf_get_addr(substream, ofs);
addr = snd_sgbuf_get_addr(dmab, ofs);
/* program the address field of the BDL entry */
bdl[0] = cpu_to_le32((u32)addr);
bdl[1] = cpu_to_le32(upper_32_bits(addr));
/* program the size field of the BDL entry */
chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
/* one BDLE cannot cross 4K boundary on CTHDA chips */
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
u32 remain = 0x1000 - (ofs & 0xfff);
@ -1478,7 +1494,8 @@ static int azx_setup_periods(struct azx *chip,
pci_name(chip->pci), bdl_pos_adj[chip->dev_index]);
pos_adj = 0;
} else {
ofs = setup_bdle(chip, substream, azx_dev,
ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
azx_dev,
&bdl, ofs, pos_adj, true);
if (ofs < 0)
goto error;
@ -1487,10 +1504,12 @@ static int azx_setup_periods(struct azx *chip,
pos_adj = 0;
for (i = 0; i < periods; i++) {
if (i == periods - 1 && pos_adj)
ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
azx_dev, &bdl, ofs,
period_bytes - pos_adj, 0);
else
ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream),
azx_dev, &bdl, ofs,
period_bytes,
!azx_dev->no_period_wakeup);
if (ofs < 0)
@ -1668,6 +1687,11 @@ static int azx_codec_create(struct azx *chip, const char *model)
bus_temp.power_save = &power_save;
bus_temp.ops.pm_notify = azx_power_notify;
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER
bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare;
bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger;
bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup;
#endif
err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
if (err < 0)
@ -2576,6 +2600,102 @@ static void azx_stop_chip(struct azx *chip)
chip->initialized = 0;
}
#ifdef CONFIG_SND_HDA_DSP_LOADER
/*
* DSP loading code (e.g. for CA0132)
*/
/* use the first stream for loading DSP */
static struct azx_dev *
azx_get_dsp_loader_dev(struct azx *chip)
{
return &chip->azx_dev[chip->playback_index_offset];
}
static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
unsigned int byte_size,
struct snd_dma_buffer *bufp)
{
u32 *bdl;
struct azx *chip = bus->private_data;
struct azx_dev *azx_dev;
int err;
if (snd_hda_lock_devices(bus))
return -EBUSY;
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
byte_size, bufp);
if (err < 0)
goto unlock;
mark_pages_wc(chip, bufp, true);
azx_dev = azx_get_dsp_loader_dev(chip);
azx_dev->bufsize = byte_size;
azx_dev->period_bytes = byte_size;
azx_dev->format_val = format;
azx_stream_reset(chip, azx_dev);
/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
azx_dev->frags = 0;
bdl = (u32 *)azx_dev->bdl.area;
err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0);
if (err < 0)
goto error;
azx_setup_controller(chip, azx_dev);
return azx_dev->stream_tag;
error:
mark_pages_wc(chip, bufp, false);
snd_dma_free_pages(bufp);
unlock:
snd_hda_unlock_devices(bus);
return err;
}
static void azx_load_dsp_trigger(struct hda_bus *bus, bool start)
{
struct azx *chip = bus->private_data;
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
if (start)
azx_stream_start(chip, azx_dev);
else
azx_stream_stop(chip, azx_dev);
azx_dev->running = start;
}
static void azx_load_dsp_cleanup(struct hda_bus *bus,
struct snd_dma_buffer *dmab)
{
struct azx *chip = bus->private_data;
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);
if (!dmab->area)
return;
/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
azx_sd_writel(azx_dev, SD_CTL, 0);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
mark_pages_wc(chip, dmab, false);
snd_dma_free_pages(dmab);
dmab->area = NULL;
snd_hda_unlock_devices(bus);
}
#endif /* CONFIG_SND_HDA_DSP_LOADER */
#ifdef CONFIG_PM
/* power-up/down the controller */
static void azx_power_notify(struct hda_bus *bus, bool power_up)
@ -2726,6 +2846,8 @@ static int azx_runtime_idle(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
if (power_save_controller > 0)
return 0;
if (!power_save_controller ||
!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
return -EBUSY;
@ -3150,6 +3272,9 @@ static void azx_check_snoop_available(struct azx *chip)
/* new ATI HDMI requires non-snoop */
snoop = false;
break;
case AZX_DRIVER_CTHDA:
snoop = false;
break;
}
if (snoop != chip->snoop) {
@ -3611,6 +3736,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Wellsburg */
{ PCI_DEVICE(0x8086, 0x8d20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x8d21),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@ -3618,13 +3748,15 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
{ PCI_DEVICE(0x8086, 0x9c21),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x0c0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x0d0c),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
/* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Poulsbo */
{ PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },

View File

@ -29,7 +29,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
AC_DEFCFG_MISC_NO_PRESENCE)
return false;
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) &&
!codec->jackpoll_interval)
return false;
return true;
}
@ -39,6 +40,7 @@ EXPORT_SYMBOL_HDA(is_jack_detectable);
static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
{
u32 pincap;
u32 val;
if (!codec->no_trigger_sense) {
pincap = snd_hda_query_pin_caps(codec, nid);
@ -46,8 +48,11 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
snd_hda_codec_read(codec, nid, 0,
AC_VERB_SET_PIN_SENSE, 0);
}
return snd_hda_codec_read(codec, nid, 0,
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_SENSE, 0);
if (codec->inv_jack_detect)
val ^= AC_PINSENSE_PRESENCE;
return val;
}
/**

View File

@ -133,9 +133,11 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val);
int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val);
#ifdef CONFIG_PM
int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val);
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val);
void snd_hda_codec_resume_amp(struct hda_codec *codec);
#endif
void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int *tlv);
@ -383,6 +385,61 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
int snd_hda_add_new_ctls(struct hda_codec *codec,
const struct snd_kcontrol_new *knew);
/*
* Fix-up pin default configurations and add default verbs
*/
struct hda_pintbl {
hda_nid_t nid;
u32 val;
};
struct hda_model_fixup {
const int id;
const char *name;
};
struct hda_fixup {
int type;
bool chained:1; /* call the chained fixup(s) after this */
bool chained_before:1; /* call the chained fixup(s) before this */
int chain_id;
union {
const struct hda_pintbl *pins;
const struct hda_verb *verbs;
void (*func)(struct hda_codec *codec,
const struct hda_fixup *fix,
int action);
} v;
};
/* fixup types */
enum {
HDA_FIXUP_INVALID,
HDA_FIXUP_PINS,
HDA_FIXUP_VERBS,
HDA_FIXUP_FUNC,
HDA_FIXUP_PINCTLS,
};
/* fixup action definitions */
enum {
HDA_FIXUP_ACT_PRE_PROBE,
HDA_FIXUP_ACT_PROBE,
HDA_FIXUP_ACT_INIT,
HDA_FIXUP_ACT_BUILD,
};
int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list);
void snd_hda_apply_verbs(struct hda_codec *codec);
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg);
void snd_hda_apply_fixup(struct hda_codec *codec, int action);
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
const struct snd_pci_quirk *quirk,
const struct hda_fixup *fixlist);
/*
* unsolicited event handler
*/
@ -431,6 +488,8 @@ struct hda_bus_unsolicited {
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
hda_nid_t pin, unsigned int val);
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
unsigned int val, bool cached);
@ -470,6 +529,10 @@ snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin,
return _snd_hda_set_pin_ctl(codec, pin, val, true);
}
int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
unsigned int val);
/*
* get widget capabilities
*/
@ -552,6 +615,7 @@ static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_RECONFIG
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key);
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key);
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp);
#else
static inline
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
@ -564,6 +628,12 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
return -ENOENT;
}
static inline
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
return -ENOENT;
}
#endif
/*
@ -587,6 +657,19 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
struct hda_loopback_check *check,
hda_nid_t nid);
/* check whether the actual power state matches with the target state */
static inline bool
snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
unsigned int target_state)
{
unsigned int state = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_POWER_STATE, 0);
if (state & AC_PWRST_ERROR)
return true;
state = (state >> 4) & 0x0f;
return (state != target_state);
}
/*
* AMP control callbacks
*/
@ -596,7 +679,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
#define get_amp_direction_(pv) (((pv) >> 18) & 0x1)
#define get_amp_direction(kc) get_amp_direction_((kc)->private_value)
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
#define get_amp_index_(pv) (((pv) >> 19) & 0xf)
#define get_amp_index(kc) get_amp_index_((kc)->private_value)
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
#define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1)
@ -629,10 +713,10 @@ struct cea_sad {
/*
* ELD: EDID Like Data
*/
struct hdmi_eld {
bool monitor_present;
bool eld_valid;
int eld_size;
struct parsed_hdmi_eld {
/*
* all fields will be cleared before updating ELD
*/
int baseline_len;
int eld_ver;
int cea_edid_ver;
@ -647,19 +731,27 @@ struct hdmi_eld {
int spk_alloc;
int sad_count;
struct cea_sad sad[ELD_MAX_SAD];
/*
* all fields above eld_buffer will be cleared before updating ELD
*/
};
struct hdmi_eld {
bool monitor_present;
bool eld_valid;
int eld_size;
char eld_buffer[ELD_MAX_SIZE];
struct parsed_hdmi_eld info;
struct mutex lock;
#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);
void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld,
int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
unsigned char *buf, int *eld_size);
int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e,
const unsigned char *buf, int size);
void snd_hdmi_show_eld(struct parsed_hdmi_eld *e);
void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
struct hda_pcm_stream *hinfo);
#ifdef CONFIG_PROC_FS

View File

@ -22,6 +22,7 @@
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
@ -138,16 +139,17 @@ static void print_amp_vals(struct snd_info_buffer *buffer,
dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
for (i = 0; i < indices; i++) {
snd_iprintf(buffer, " [");
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_LEFT | dir | i);
snd_iprintf(buffer, "0x%02x", val);
if (stereo) {
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_LEFT | dir | i);
snd_iprintf(buffer, "0x%02x ", val);
AC_AMP_GET_RIGHT | dir | i);
snd_iprintf(buffer, " 0x%02x", val);
}
val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_AMP_GAIN_MUTE,
AC_AMP_GET_RIGHT | dir | i);
snd_iprintf(buffer, "0x%02x]", val);
snd_iprintf(buffer, "]");
}
snd_iprintf(buffer, "\n");
}
@ -603,6 +605,8 @@ static void print_codec_info(struct snd_info_entry *entry,
print_amp_caps(buffer, codec, codec->afg, HDA_INPUT);
snd_iprintf(buffer, "Default Amp-Out caps: ");
print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT);
snd_iprintf(buffer, "State of AFG node 0x%02x:\n", codec->afg);
print_power_state(buffer, codec, codec->afg);
nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
if (! nid || nodes < 0) {
@ -620,7 +624,7 @@ static void print_codec_info(struct snd_info_entry *entry,
snd_hda_param_read(codec, nid,
AC_PAR_AUDIO_WIDGET_CAP);
unsigned int wid_type = get_wcaps_type(wid_caps);
hda_nid_t conn[HDA_MAX_CONNECTIONS];
hda_nid_t *conn = NULL;
int conn_len = 0;
snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
@ -657,9 +661,18 @@ static void print_codec_info(struct snd_info_entry *entry,
if (wid_type == AC_WID_VOL_KNB)
wid_caps |= AC_WCAP_CONN_LIST;
if (wid_caps & AC_WCAP_CONN_LIST)
conn_len = snd_hda_get_raw_connections(codec, nid, conn,
HDA_MAX_CONNECTIONS);
if (wid_caps & AC_WCAP_CONN_LIST) {
conn_len = snd_hda_get_num_raw_conns(codec, nid);
if (conn_len > 0) {
conn = kmalloc(sizeof(hda_nid_t) * conn_len,
GFP_KERNEL);
if (!conn)
return;
if (snd_hda_get_raw_connections(codec, nid, conn,
conn_len) < 0)
conn_len = 0;
}
}
if (wid_caps & AC_WCAP_IN_AMP) {
snd_iprintf(buffer, " Amp-In caps: ");
@ -732,6 +745,8 @@ static void print_codec_info(struct snd_info_entry *entry,
if (codec->proc_widget_hook)
codec->proc_widget_hook(buffer, codec, nid);
kfree(conn);
}
snd_hda_power_down(codec);
}

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,6 @@
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/module.h>
@ -27,502 +26,46 @@
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
#include "hda_generic.h"
/*
*/
struct ca0110_spec {
struct auto_pin_cfg autocfg;
struct hda_multi_out multiout;
hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
hda_nid_t hp_dac;
hda_nid_t input_pins[AUTO_PIN_LAST];
hda_nid_t adcs[AUTO_PIN_LAST];
hda_nid_t dig_out;
hda_nid_t dig_in;
unsigned int num_inputs;
char input_labels[AUTO_PIN_LAST][32];
struct hda_pcm pcm_rec[2]; /* PCM information */
};
/*
* PCM callbacks
*/
static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo);
}
static int ca0110_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 ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
stream_tag, format, substream);
}
static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
/*
* Digital out
*/
static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
}
static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
}
static int ca0110_dig_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 ca0110_spec *spec = codec->spec;
return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
format, substream);
}
/*
* Analog capture
*/
static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
snd_hda_codec_setup_stream(codec, spec->adcs[substream->number],
stream_tag, 0, format);
return 0;
}
static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream)
{
struct ca0110_spec *spec = codec->spec;
snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]);
return 0;
}
/*
*/
static const char * const dirstr[2] = { "Playback", "Capture" };
static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
int chan, int dir)
{
char namestr[44];
int type = dir ? HDA_INPUT : HDA_OUTPUT;
struct snd_kcontrol_new knew =
HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
}
static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
int chan, int dir)
{
char namestr[44];
int type = dir ? HDA_INPUT : HDA_OUTPUT;
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
}
#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0)
#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0)
#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1)
#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1)
#define add_mono_switch(codec, nid, pfx, chan) \
_add_switch(codec, nid, pfx, chan, 0)
#define add_mono_volume(codec, nid, pfx, chan) \
_add_volume(codec, nid, pfx, chan, 0)
static int ca0110_build_controls(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
static const char * const prefix[AUTO_CFG_MAX_OUTS] = {
"Front", "Surround", NULL, "Side", "Multi"
};
hda_nid_t mutenid;
int i, err;
for (i = 0; i < spec->multiout.num_dacs; i++) {
if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP)
mutenid = spec->out_pins[i];
else
mutenid = spec->multiout.dac_nids[i];
if (!prefix[i]) {
err = add_mono_switch(codec, mutenid,
"Center", 1);
if (err < 0)
return err;
err = add_mono_switch(codec, mutenid,
"LFE", 1);
if (err < 0)
return err;
err = add_mono_volume(codec, spec->multiout.dac_nids[i],
"Center", 1);
if (err < 0)
return err;
err = add_mono_volume(codec, spec->multiout.dac_nids[i],
"LFE", 1);
if (err < 0)
return err;
} else {
err = add_out_switch(codec, mutenid,
prefix[i]);
if (err < 0)
return err;
err = add_out_volume(codec, spec->multiout.dac_nids[i],
prefix[i]);
if (err < 0)
return err;
}
}
if (cfg->hp_outs) {
if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP)
mutenid = cfg->hp_pins[0];
else
mutenid = spec->multiout.dac_nids[i];
err = add_out_switch(codec, mutenid, "Headphone");
if (err < 0)
return err;
if (spec->hp_dac) {
err = add_out_volume(codec, spec->hp_dac, "Headphone");
if (err < 0)
return err;
}
}
for (i = 0; i < spec->num_inputs; i++) {
const char *label = spec->input_labels[i];
if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP)
mutenid = spec->input_pins[i];
else
mutenid = spec->adcs[i];
err = add_in_switch(codec, mutenid, label);
if (err < 0)
return err;
err = add_in_volume(codec, spec->adcs[i], label);
if (err < 0)
return err;
}
if (spec->dig_out) {
err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
spec->dig_out);
if (err < 0)
return err;
err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
if (err < 0)
return err;
spec->multiout.share_spdif = 1;
}
if (spec->dig_in) {
err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
if (err < 0)
return err;
err = add_in_volume(codec, spec->dig_in, "IEC958");
}
return 0;
}
/*
*/
static const struct hda_pcm_stream ca0110_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 8,
.ops = {
.open = ca0110_playback_pcm_open,
.prepare = ca0110_playback_pcm_prepare,
.cleanup = ca0110_playback_pcm_cleanup
},
};
static const struct hda_pcm_stream ca0110_pcm_analog_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.ops = {
.prepare = ca0110_capture_pcm_prepare,
.cleanup = ca0110_capture_pcm_cleanup
},
};
static const struct hda_pcm_stream ca0110_pcm_digital_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
.ops = {
.open = ca0110_dig_playback_pcm_open,
.close = ca0110_dig_playback_pcm_close,
.prepare = ca0110_dig_playback_pcm_prepare
},
};
static const struct hda_pcm_stream ca0110_pcm_digital_capture = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
};
static int ca0110_build_pcms(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec;
codec->pcm_info = info;
codec->num_pcms = 0;
info->name = "CA0110 Analog";
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
spec->multiout.max_channels;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
codec->num_pcms++;
if (!spec->dig_out && !spec->dig_in)
return 0;
info++;
info->name = "CA0110 Digital";
info->pcm_type = HDA_PCM_TYPE_SPDIF;
if (spec->dig_out) {
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
ca0110_pcm_digital_playback;
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
}
if (spec->dig_in) {
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
ca0110_pcm_digital_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
}
codec->num_pcms++;
return 0;
}
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
{
if (pin) {
snd_hda_set_pin_ctl(codec, pin, PIN_HP);
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
}
if (dac)
snd_hda_codec_write(codec, dac, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
}
static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
{
if (pin) {
snd_hda_set_pin_ctl(codec, pin, PIN_IN |
snd_hda_get_default_vref(codec, pin));
if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0));
}
if (adc)
snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_UNMUTE(0));
}
static int ca0110_init(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
for (i = 0; i < spec->multiout.num_dacs; i++)
init_output(codec, spec->out_pins[i],
spec->multiout.dac_nids[i]);
init_output(codec, cfg->hp_pins[0], spec->hp_dac);
init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
for (i = 0; i < spec->num_inputs; i++)
init_input(codec, spec->input_pins[i], spec->adcs[i]);
init_input(codec, cfg->dig_in_pin, spec->dig_in);
return 0;
}
static void ca0110_free(struct hda_codec *codec)
{
kfree(codec->spec);
}
static const struct hda_codec_ops ca0110_patch_ops = {
.build_controls = ca0110_build_controls,
.build_pcms = ca0110_build_pcms,
.init = ca0110_init,
.free = ca0110_free,
.build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = snd_hda_gen_init,
.free = snd_hda_gen_free,
.unsol_event = snd_hda_jack_unsol_event,
};
static void parse_line_outs(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i, n;
unsigned int def_conf;
hda_nid_t nid;
n = 0;
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
def_conf = snd_hda_codec_get_pincfg(codec, nid);
if (!def_conf)
continue; /* invalid pin */
if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1)
continue;
spec->out_pins[n++] = nid;
}
spec->multiout.dac_nids = spec->dacs;
spec->multiout.num_dacs = n;
spec->multiout.max_channels = n * 2;
}
static void parse_hp_out(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
int i;
unsigned int def_conf;
hda_nid_t nid, dac;
if (!cfg->hp_outs)
return;
nid = cfg->hp_pins[0];
def_conf = snd_hda_codec_get_pincfg(codec, nid);
if (!def_conf) {
cfg->hp_outs = 0;
return;
}
if (snd_hda_get_connections(codec, nid, &dac, 1) != 1)
return;
for (i = 0; i < cfg->line_outs; i++)
if (dac == spec->dacs[i])
break;
if (i >= cfg->line_outs) {
spec->hp_dac = dac;
spec->multiout.hp_nid = dac;
}
}
static void parse_input(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
hda_nid_t nid, pin;
int n, i, j;
n = 0;
nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) {
unsigned int wcaps = get_wcaps(codec, nid);
unsigned int type = get_wcaps_type(wcaps);
if (type != AC_WID_AUD_IN)
continue;
if (snd_hda_get_connections(codec, nid, &pin, 1) != 1)
continue;
if (pin == cfg->dig_in_pin) {
spec->dig_in = nid;
continue;
}
for (j = 0; j < cfg->num_inputs; j++)
if (cfg->inputs[j].pin == pin)
break;
if (j >= cfg->num_inputs)
continue;
spec->input_pins[n] = pin;
snd_hda_get_pin_label(codec, pin, cfg,
spec->input_labels[n],
sizeof(spec->input_labels[n]), NULL);
spec->adcs[n] = nid;
n++;
}
spec->num_inputs = n;
}
static void parse_digital(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
if (cfg->dig_outs &&
snd_hda_get_connections(codec, cfg->dig_out_pins[0],
&spec->dig_out, 1) == 1)
spec->multiout.dig_out_nid = spec->dig_out;
}
static int ca0110_parse_auto_config(struct hda_codec *codec)
{
struct ca0110_spec *spec = codec->spec;
struct hda_gen_spec *spec = codec->spec;
int err;
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
if (err < 0)
return err;
err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
if (err < 0)
return err;
parse_line_outs(codec);
parse_hp_out(codec);
parse_digital(codec);
parse_input(codec);
return 0;
}
static int patch_ca0110(struct hda_codec *codec)
{
struct ca0110_spec *spec;
struct hda_gen_spec *spec;
int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
snd_hda_gen_spec_init(spec);
codec->spec = spec;
spec->multi_cap_vol = 1;
codec->bus->needs_damn_long_delay = 1;
err = ca0110_parse_auto_config(codec);
@ -534,8 +77,7 @@ static int patch_ca0110(struct hda_codec *codec)
return 0;
error:
kfree(codec->spec);
codec->spec = NULL;
snd_hda_gen_free(codec);
return err;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,6 @@
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/module.h>
@ -30,6 +29,9 @@
#include "hda_codec.h"
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
#include "hda_generic.h"
#define NUM_PINS 11
@ -45,6 +47,10 @@ enum {
};
struct cmi_spec {
struct hda_gen_spec gen;
/* below are only for static models */
int board_config;
unsigned int no_line_in: 1; /* no line-in (5-jack) */
unsigned int front_panel: 1; /* has front-panel 2-jack */
@ -356,77 +362,6 @@ static int cmi9880_build_controls(struct hda_codec *codec)
return 0;
}
/* fill in the multi_dac_nids table, which will decide
which audio widget to use for each channel */
static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
{
struct cmi_spec *spec = codec->spec;
hda_nid_t nid;
int assigned[4];
int i, j;
/* clear the table, only one c-media dac assumed here */
memset(spec->dac_nids, 0, sizeof(spec->dac_nids));
memset(assigned, 0, sizeof(assigned));
/* check the pins we found */
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
/* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */
if (nid >= 0x0b && nid <= 0x0e) {
spec->dac_nids[i] = (nid - 0x0b) + 0x03;
assigned[nid - 0x0b] = 1;
}
}
/* left pin can be connect to any audio widget */
for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
if (nid <= 0x0e)
continue;
/* search for an empty channel */
for (j = 0; j < cfg->line_outs; j++) {
if (! assigned[j]) {
spec->dac_nids[i] = j + 0x03;
assigned[j] = 1;
break;
}
}
}
spec->num_dacs = cfg->line_outs;
return 0;
}
/* create multi_init table, which is used for multichannel initialization */
static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
{
struct cmi_spec *spec = codec->spec;
hda_nid_t nid;
int i, j, k;
/* clear the table, only one c-media dac assumed here */
memset(spec->multi_init, 0, sizeof(spec->multi_init));
for (j = 0, i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
/* set as output */
spec->multi_init[j].nid = nid;
spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL;
spec->multi_init[j].param = PIN_OUT;
j++;
if (nid > 0x0e) {
/* set connection */
spec->multi_init[j].nid = nid;
spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL;
spec->multi_init[j].param = 0;
/* find the index in connect list */
k = snd_hda_get_conn_index(codec, nid,
spec->dac_nids[i], 0);
if (k >= 0)
spec->multi_init[j].param = k;
j++;
}
}
return 0;
}
static int cmi9880_init(struct hda_codec *codec)
{
struct cmi_spec *spec = codec->spec;
@ -632,6 +567,36 @@ static const struct hda_codec_ops cmi9880_patch_ops = {
.free = cmi9880_free,
};
/*
* stuff for auto-parser
*/
static const struct hda_codec_ops cmi_auto_patch_ops = {
.build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = snd_hda_gen_init,
.free = snd_hda_gen_free,
.unsol_event = snd_hda_jack_unsol_event,
};
static int cmi_parse_auto_config(struct hda_codec *codec)
{
struct cmi_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
int err;
snd_hda_gen_spec_init(&spec->gen);
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
if (err < 0)
return err;
err = snd_hda_gen_parse_auto_config(codec, cfg);
if (err < 0)
return err;
codec->patch_ops = cmi_auto_patch_ops;
return 0;
}
static int patch_cmi9880(struct hda_codec *codec)
{
struct cmi_spec *spec;
@ -650,6 +615,15 @@ static int patch_cmi9880(struct hda_codec *codec)
spec->board_config = CMI_AUTO; /* try everything */
}
if (spec->board_config == CMI_AUTO) {
int err = cmi_parse_auto_config(codec);
if (err < 0) {
snd_hda_gen_free(codec);
return err;
}
return 0;
}
/* copy default DAC NIDs */
memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids));
spec->num_dacs = 4;
@ -678,59 +652,13 @@ static int patch_cmi9880(struct hda_codec *codec)
}
break;
case CMI_ALLOUT:
default:
spec->front_panel = 1;
spec->multiout.max_channels = 8;
spec->no_line_in = 1;
spec->input_mux = &cmi9880_no_line_mux;
spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
break;
case CMI_AUTO:
{
unsigned int port_e, port_f, port_g, port_h;
unsigned int port_spdifi, port_spdifo;
struct auto_pin_cfg cfg;
/* collect pin default configuration */
port_e = snd_hda_codec_get_pincfg(codec, 0x0f);
port_f = snd_hda_codec_get_pincfg(codec, 0x10);
spec->front_panel = 1;
if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE ||
get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) {
port_g = snd_hda_codec_get_pincfg(codec, 0x1f);
port_h = snd_hda_codec_get_pincfg(codec, 0x20);
spec->channel_modes = cmi9880_channel_modes;
/* no front panel */
if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE ||
get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) {
/* no optional rear panel */
spec->board_config = CMI_MINIMAL;
spec->front_panel = 0;
spec->num_channel_modes = 2;
} else {
spec->board_config = CMI_MIN_FP;
spec->num_channel_modes = 3;
}
spec->input_mux = &cmi9880_basic_mux;
spec->multiout.max_channels = cmi9880_channel_modes[0].channels;
} else {
spec->input_mux = &cmi9880_basic_mux;
port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13);
port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12);
if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE)
spec->multiout.dig_out_nid = CMI_DIG_OUT_NID;
if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE)
spec->dig_in_nid = CMI_DIG_IN_NID;
spec->multiout.max_channels = 8;
}
snd_hda_parse_pin_def_config(codec, &cfg, NULL);
if (cfg.line_outs) {
spec->multiout.max_channels = cfg.line_outs * 2;
cmi9880_fill_multi_dac_nids(codec, &cfg);
cmi9880_fill_multi_init(codec, &cfg);
} else
snd_printd("patch_cmedia: cannot detect association in defcfg\n");
break;
}
}
spec->multiout.num_dacs = spec->num_dacs;

File diff suppressed because it is too large Load Diff

View File

@ -64,6 +64,9 @@ struct hdmi_spec_per_cvt {
unsigned int maxbps;
};
/* max. connections to a widget */
#define HDA_MAX_CONNECTIONS 32
struct hdmi_spec_per_pin {
hda_nid_t pin_nid;
int num_mux_nids;
@ -72,6 +75,7 @@ struct hdmi_spec_per_pin {
struct hda_codec *codec;
struct hdmi_eld sink_eld;
struct delayed_work work;
struct snd_kcontrol *eld_ctl;
int repoll_count;
bool non_pcm;
bool chmap_set; /* channel-map override by ALSA API? */
@ -81,12 +85,14 @@ struct hdmi_spec_per_pin {
struct hdmi_spec {
int num_cvts;
struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS];
hda_nid_t cvt_nids[MAX_HDMI_CVTS];
int num_pins;
struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
struct hda_pcm pcm_rec[MAX_HDMI_PINS];
unsigned int channels_max; /* max over all cvts */
struct hdmi_eld temp_eld;
/*
* Non-generic ATI/NVIDIA specific
*/
@ -339,14 +345,18 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hdmi_spec *spec;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld;
int pin_idx;
spec = codec->spec;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
pin_idx = kcontrol->private_value;
uinfo->count = spec->pins[pin_idx].sink_eld.eld_size;
eld = &spec->pins[pin_idx].sink_eld;
mutex_lock(&eld->lock);
uinfo->count = eld->eld_valid ? eld->eld_size : 0;
mutex_unlock(&eld->lock);
return 0;
}
@ -355,14 +365,26 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hdmi_spec *spec;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld;
int pin_idx;
spec = codec->spec;
pin_idx = kcontrol->private_value;
eld = &spec->pins[pin_idx].sink_eld;
memcpy(ucontrol->value.bytes.data,
spec->pins[pin_idx].sink_eld.eld_buffer, ELD_MAX_SIZE);
mutex_lock(&eld->lock);
if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
mutex_unlock(&eld->lock);
snd_BUG();
return -EINVAL;
}
memset(ucontrol->value.bytes.data, 0,
ARRAY_SIZE(ucontrol->value.bytes.data));
if (eld->eld_valid)
memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
eld->eld_size);
mutex_unlock(&eld->lock);
return 0;
}
@ -392,6 +414,7 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
if (err < 0)
return err;
spec->pins[pin_idx].eld_ctl = kctl;
return 0;
}
@ -516,7 +539,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
* 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))
if (eld->info.spk_alloc & (1 << i))
spk_mask |= eld_speaker_allocation_bits[i];
}
@ -530,7 +553,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
}
}
snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf));
snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
ca, channels, buf);
@ -714,9 +737,10 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
static void hdmi_setup_channel_mapping(struct hda_codec *codec,
hda_nid_t pin_nid, bool non_pcm, int ca,
int channels, unsigned char *map)
int channels, unsigned char *map,
bool chmap_set)
{
if (!non_pcm && map) {
if (!non_pcm && chmap_set) {
hdmi_manual_setup_channel_mapping(codec, pin_nid,
channels, map);
} else {
@ -870,7 +894,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
ca = 0;
memset(&ai, 0, sizeof(ai));
if (eld->conn_type == 0) { /* HDMI */
if (eld->info.conn_type == 0) { /* HDMI */
struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
hdmi_ai->type = 0x84;
@ -879,7 +903,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
hdmi_ai->CC02_CT47 = channels - 1;
hdmi_ai->CA = ca;
hdmi_checksum_audio_infoframe(hdmi_ai);
} else if (eld->conn_type == 1) { /* DisplayPort */
} else if (eld->info.conn_type == 1) { /* DisplayPort */
struct dp_audio_infoframe *dp_ai = &ai.dp;
dp_ai->type = 0x84;
@ -905,7 +929,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
pin_nid,
channels);
hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
channels, per_pin->chmap);
channels, per_pin->chmap,
per_pin->chmap_set);
hdmi_stop_infoframe_trans(codec, pin_nid);
hdmi_fill_audio_infoframe(codec, pin_nid,
ai.bytes, sizeof(ai));
@ -915,7 +940,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
* accordingly */
if (per_pin->non_pcm != non_pcm)
hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
channels, per_pin->chmap);
channels, per_pin->chmap,
per_pin->chmap_set);
}
per_pin->non_pcm = non_pcm;
@ -1098,10 +1124,14 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
/* Restrict capabilities by ELD if this isn't disabled */
if (!static_hdmi_pcm && eld->eld_valid) {
snd_hdmi_eld_update_pcm_info(eld, hinfo);
snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
if (hinfo->channels_min > hinfo->channels_max ||
!hinfo->rates || !hinfo->formats)
!hinfo->rates || !hinfo->formats) {
per_cvt->assigned = 0;
hinfo->nid = 0;
snd_hda_spdif_ctls_unassign(codec, pin_idx);
return -ENODEV;
}
}
/* Store the updated parameters */
@ -1142,7 +1172,9 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
{
struct hda_codec *codec = per_pin->codec;
struct hdmi_eld *eld = &per_pin->sink_eld;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld = &spec->temp_eld;
struct hdmi_eld *pin_eld = &per_pin->sink_eld;
hda_nid_t pin_nid = per_pin->pin_nid;
/*
* Always execute a GetPinSense verb here, even when called from
@ -1153,27 +1185,64 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
* the unsolicited response to avoid custom WARs.
*/
int present = snd_hda_pin_sense(codec, pin_nid);
bool eld_valid = false;
bool update_eld = false;
bool eld_changed = false;
memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer));
eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
if (eld->monitor_present)
eld_valid = !!(present & AC_PINSENSE_ELDV);
pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
if (pin_eld->monitor_present)
eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
else
eld->eld_valid = false;
_snd_printd(SND_PR_VERBOSE,
"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, pin_nid, eld->monitor_present, eld_valid);
codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
if (eld_valid) {
if (!snd_hdmi_get_eld(eld, codec, pin_nid))
snd_hdmi_show_eld(eld);
if (eld->eld_valid) {
if (snd_hdmi_get_eld(codec, pin_nid, eld->eld_buffer,
&eld->eld_size) < 0)
eld->eld_valid = false;
else {
memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld));
if (snd_hdmi_parse_eld(&eld->info, eld->eld_buffer,
eld->eld_size) < 0)
eld->eld_valid = false;
}
if (eld->eld_valid) {
snd_hdmi_show_eld(&eld->info);
update_eld = true;
}
else if (repoll) {
queue_delayed_work(codec->bus->workq,
&per_pin->work,
msecs_to_jiffies(300));
return;
}
}
mutex_lock(&pin_eld->lock);
if (pin_eld->eld_valid && !eld->eld_valid) {
update_eld = true;
eld_changed = true;
}
if (update_eld) {
pin_eld->eld_valid = eld->eld_valid;
eld_changed = pin_eld->eld_size != eld->eld_size ||
memcmp(pin_eld->eld_buffer, eld->eld_buffer,
eld->eld_size) != 0;
if (eld_changed)
memcpy(pin_eld->eld_buffer, eld->eld_buffer,
eld->eld_size);
pin_eld->eld_size = eld->eld_size;
pin_eld->info = eld->info;
}
mutex_unlock(&pin_eld->lock);
if (eld_changed)
snd_ctl_notify(codec->bus->card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&per_pin->eld_ctl->id);
}
static void hdmi_repoll_eld(struct work_struct *work)
@ -1187,6 +1256,9 @@ static void hdmi_repoll_eld(struct work_struct *work)
hdmi_present_sense(per_pin, per_pin->repoll_count);
}
static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid);
static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
{
struct hdmi_spec *spec = codec->spec;
@ -1206,6 +1278,9 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
return -E2BIG;
if (codec->vendor_id == 0x80862807)
intel_haswell_fixup_connect_list(codec, pin_nid);
pin_idx = spec->num_pins;
per_pin = &spec->pins[pin_idx];
@ -1253,7 +1328,7 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
if (err < 0)
return err;
spec->num_cvts++;
spec->cvt_nids[spec->num_cvts++] = cvt_nid;
return 0;
}
@ -1635,6 +1710,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec)
struct hdmi_eld *eld = &per_pin->sink_eld;
per_pin->codec = codec;
mutex_init(&eld->lock);
INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
snd_hda_eld_proc_new(codec, eld, pin_idx);
}
@ -1681,30 +1757,92 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
.unsol_event = hdmi_unsol_event,
};
static void intel_haswell_fixup_connect_list(struct hda_codec *codec)
static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid)
{
struct hdmi_spec *spec = codec->spec;
hda_nid_t conns[4];
int nconns;
nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns));
if (nconns == spec->num_cvts &&
!memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t)))
return;
/* override pins connection list */
snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
}
#define INTEL_VENDOR_NID 0x08
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
static void intel_haswell_enable_all_pins(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
unsigned int vendor_param;
hda_nid_t list[3] = {0x2, 0x3, 0x4};
vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
if (vendor_param == -1 || vendor_param & 0x02)
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
return;
vendor_param |= INTEL_EN_ALL_PIN_CVTS;
vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1)
return;
snd_hda_codec_update_widgets(codec);
return;
}
static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
{
unsigned int vendor_param;
vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
return;
/* enable DP1.2 mode */
vendor_param |= 0x02;
snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param);
vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
if (vendor_param == -1 || !(vendor_param & 0x02))
return;
/* override 3 pins connection list */
snd_hda_override_conn_list(codec, 0x05, 3, list);
snd_hda_override_conn_list(codec, 0x06, 3, list);
snd_hda_override_conn_list(codec, 0x07, 3, list);
vendor_param |= INTEL_EN_DP12;
snd_hda_codec_write_cache(codec, INTEL_VENDOR_NID, 0,
INTEL_SET_VENDOR_VERB, vendor_param);
}
/* available models for fixup */
enum {
INTEL_HASWELL,
};
static const struct hda_model_fixup hdmi_models[] = {
{.id = INTEL_HASWELL, .name = "Haswell"},
{}
};
static const struct snd_pci_quirk hdmi_fixup_tbl[] = {
SND_PCI_QUIRK(0x8086, 0x2010, "Haswell", INTEL_HASWELL),
{} /* terminator */
};
static const struct hda_fixup hdmi_fixups[] = {
[INTEL_HASWELL] = {
.type = HDA_FIXUP_FUNC,
.v.func = intel_haswell_enable_all_pins,
},
};
static int patch_generic_hdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
@ -1715,8 +1853,11 @@ static int patch_generic_hdmi(struct hda_codec *codec)
codec->spec = spec;
snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
if (codec->vendor_id == 0x80862807)
intel_haswell_fixup_connect_list(codec);
intel_haswell_fixup_enable_dp12(codec);
if (hdmi_parse_codec(codec) < 0) {
codec->spec = NULL;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@
static void snd_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data)
{
if (addr < WM8766_REG_RESET)
if (addr < WM8766_REG_COUNT)
wm->regs[addr] = data;
wm->ops.write(wm, addr, data);
}

View File

@ -3266,11 +3266,13 @@ static int check_default_spdif_aclink(struct pci_dev *pci)
w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
if (w) {
if (w->value)
snd_printdd(KERN_INFO "intel8x0: Using SPDIF over "
"AC-Link for %s\n", w->name);
snd_printdd(KERN_INFO
"intel8x0: Using SPDIF over AC-Link for %s\n",
snd_pci_quirk_name(w));
else
snd_printdd(KERN_INFO "intel8x0: Using integrated "
"SPDIF DMA for %s\n", w->name);
snd_printdd(KERN_INFO
"intel8x0: Using integrated SPDIF DMA for %s\n",
snd_pci_quirk_name(w));
return w->value;
}
return 0;

View File

@ -2586,8 +2586,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
else {
quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list);
if (quirk) {
snd_printdd(KERN_INFO "maestro3: set amp-gpio "
"for '%s'\n", quirk->name);
snd_printdd(KERN_INFO
"maestro3: set amp-gpio for '%s'\n",
snd_pci_quirk_name(quirk));
chip->amp_gpio = quirk->value;
} else if (chip->allegro_flag)
chip->amp_gpio = GPO_EXT_AMP_ALLEGRO;
@ -2597,8 +2598,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list);
if (quirk) {
snd_printdd(KERN_INFO "maestro3: enabled irda workaround "
"for '%s'\n", quirk->name);
snd_printdd(KERN_INFO
"maestro3: enabled irda workaround for '%s'\n",
snd_pci_quirk_name(quirk));
chip->irda_workaround = 1;
}
quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list);

View File

@ -1660,7 +1660,8 @@ static int snd_nm256_probe(struct pci_dev *pci,
q = snd_pci_quirk_lookup(pci, nm256_quirks);
if (q) {
snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name);
snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n",
snd_pci_quirk_name(q));
switch (q->value) {
case NM_BLACKLISTED:
printk(KERN_INFO "nm256: The device is blacklisted. "

View File

@ -1012,13 +1012,12 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
enum pcxhr_async_err_src err_src, int pipe,
int is_capture)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
static char* err_src_name[] = {
[PCXHR_ERR_PIPE] = "Pipe",
[PCXHR_ERR_STREAM] = "Stream",
[PCXHR_ERR_AUDIO] = "Audio"
};
#endif
if (err & 0xfff)
err &= 0xfff;
else

View File

@ -1017,7 +1017,7 @@ static int snd_rme32_capture_close(struct snd_pcm_substream *substream)
spin_lock_irq(&rme32->lock);
rme32->capture_substream = NULL;
rme32->capture_periodsize = 0;
spin_unlock(&rme32->lock);
spin_unlock_irq(&rme32->lock);
return 0;
}

View File

@ -154,10 +154,13 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
#define HDSP_BIGENDIAN_MODE 0x200
#define HDSP_RD_MULTIPLE 0x400
#define HDSP_9652_ENABLE_MIXER 0x800
#define HDSP_S200 0x800
#define HDSP_S300 (0x100 | HDSP_S200) /* dummy, purpose of 0x100 unknown */
#define HDSP_CYCLIC_MODE 0x1000
#define HDSP_TDO 0x10000000
#define HDSP_S_PROGRAM (HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
#define HDSP_S_LOAD (HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
#define HDSP_S_PROGRAM (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_0)
#define HDSP_S_LOAD (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_1)
/* Control Register bits */
@ -671,13 +674,23 @@ static unsigned int hdsp_read(struct hdsp *hdsp, int reg)
static int hdsp_check_for_iobox (struct hdsp *hdsp)
{
int i;
if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) {
snd_printk("Hammerfall-DSP: no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
for (i = 0; i < 500; i++) {
if (0 == (hdsp_read(hdsp, HDSP_statusRegister) &
HDSP_ConfigError)) {
if (i) {
snd_printd("Hammerfall-DSP: IO box found after %d ms\n",
(20 * i));
}
return 0;
}
msleep(20);
}
return 0;
snd_printk(KERN_ERR "Hammerfall-DSP: no IO box connected!\n");
hdsp->state &= ~HDSP_FirmwareLoaded;
return -EIO;
}
static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
@ -728,6 +741,7 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n");
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
return -EIO;
}
@ -737,17 +751,15 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
hdsp_write(hdsp, HDSP_fifoData, cache[i]);
if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) {
snd_printk ("Hammerfall-DSP: timeout during firmware loading\n");
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
return -EIO;
}
}
hdsp_fifo_wait(hdsp, 3, HDSP_LONG_WAIT);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200);
ssleep(3);
if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
snd_printk ("Hammerfall-DSP: timeout at end of firmware loading\n");
return -EIO;
}
#ifdef SNDRV_BIG_ENDIAN
hdsp->control2_register = HDSP_BIGENDIAN_MODE;
#else
@ -773,24 +785,51 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
{
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM);
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0)
return -EIO;
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) {
hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT))
hdsp->io_type = RPM;
else
hdsp->io_type = Multiface;
} else {
hdsp->io_type = Digiface;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200 | HDSP_PROGRAM);
hdsp_write (hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp->io_type = Multiface;
snd_printk("Hammerfall-DSP: Multiface found\n");
return 0;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
hdsp->io_type = Digiface;
snd_printk("Hammerfall-DSP: Digiface found\n");
return 0;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) {
hdsp->io_type = Multiface;
snd_printk("Hammerfall-DSP: Multiface found\n");
return 0;
}
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300);
hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
hdsp_write(hdsp, HDSP_fifoData, 0);
if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) {
hdsp->io_type = Multiface;
snd_printk("Hammerfall-DSP: Multiface found\n");
return 0;
}
hdsp->io_type = RPM;
snd_printk("Hammerfall-DSP: RPM found\n");
return 0;
} else {
/* firmware was already loaded, get iobox type */
if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
@ -1674,83 +1713,50 @@ static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return change;
}
#define HDSP_SPDIF_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out }
static int hdsp_spdif_out(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFOpticalOut) ? 1 : 0;
#define HDSP_TOGGLE_SETTING(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.private_value = xindex, \
.info = snd_hdsp_info_toggle_setting, \
.get = snd_hdsp_get_toggle_setting, \
.put = snd_hdsp_put_toggle_setting \
}
static int hdsp_set_spdif_output(struct hdsp *hdsp, int out)
static int hdsp_toggle_setting(struct hdsp *hdsp, u32 regmask)
{
return (hdsp->control_register & regmask) ? 1 : 0;
}
static int hdsp_set_toggle_setting(struct hdsp *hdsp, u32 regmask, int out)
{
if (out)
hdsp->control_register |= HDSP_SPDIFOpticalOut;
hdsp->control_register |= regmask;
else
hdsp->control_register &= ~HDSP_SPDIFOpticalOut;
hdsp->control_register &= ~regmask;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_spdif_bits snd_ctl_boolean_mono_info
#define snd_hdsp_info_toggle_setting snd_ctl_boolean_mono_info
static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
static int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
u32 regmask = kcontrol->private_value;
ucontrol->value.integer.value[0] = hdsp_spdif_out(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_out(hdsp);
hdsp_set_spdif_output(hdsp, val);
ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional }
static int hdsp_spdif_professional(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFProfessional) ? 1 : 0;
}
static int hdsp_set_spdif_professional(struct hdsp *hdsp, int val)
{
if (val)
hdsp->control_register |= HDSP_SPDIFProfessional;
else
hdsp->control_register &= ~HDSP_SPDIFProfessional;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
static int snd_hdsp_get_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = hdsp_spdif_professional(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
u32 regmask = kcontrol->private_value;
int change;
unsigned int val;
@ -1758,96 +1764,9 @@ static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_professional(hdsp);
hdsp_set_spdif_professional(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_SPDIF_EMPHASIS(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis }
static int hdsp_spdif_emphasis(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFEmphasis) ? 1 : 0;
}
static int hdsp_set_spdif_emphasis(struct hdsp *hdsp, int val)
{
if (val)
hdsp->control_register |= HDSP_SPDIFEmphasis;
else
hdsp->control_register &= ~HDSP_SPDIFEmphasis;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
static int snd_hdsp_get_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = hdsp_spdif_emphasis(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_emphasis(hdsp);
hdsp_set_spdif_emphasis(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_SPDIF_NON_AUDIO(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio }
static int hdsp_spdif_nonaudio(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_SPDIFNonAudio) ? 1 : 0;
}
static int hdsp_set_spdif_nonaudio(struct hdsp *hdsp, int val)
{
if (val)
hdsp->control_register |= HDSP_SPDIFNonAudio;
else
hdsp->control_register &= ~HDSP_SPDIFNonAudio;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
static int snd_hdsp_get_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] = hdsp_spdif_nonaudio(hdsp);
return 0;
}
static int snd_hdsp_put_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_spdif_nonaudio(hdsp);
hdsp_set_spdif_nonaudio(hdsp, val);
change = (int) val != hdsp_toggle_setting(hdsp, regmask);
if (change)
hdsp_set_toggle_setting(hdsp, regmask, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
@ -2451,114 +2370,6 @@ static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl
return change;
}
#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_xlr_breakout_cable, \
.get = snd_hdsp_get_xlr_breakout_cable, \
.put = snd_hdsp_put_xlr_breakout_cable \
}
static int hdsp_xlr_breakout_cable(struct hdsp *hdsp)
{
if (hdsp->control_register & HDSP_XLRBreakoutCable)
return 1;
return 0;
}
static int hdsp_set_xlr_breakout_cable(struct hdsp *hdsp, int mode)
{
if (mode)
hdsp->control_register |= HDSP_XLRBreakoutCable;
else
hdsp->control_register &= ~HDSP_XLRBreakoutCable;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_xlr_breakout_cable snd_ctl_boolean_mono_info
static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp);
return 0;
}
static int snd_hdsp_put_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_xlr_breakout_cable(hdsp);
hdsp_set_xlr_breakout_cable(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
/* (De)activates old RME Analog Extension Board
These are connected to the internal ADAT connector
Switching this on desactivates external ADAT
*/
#define HDSP_AEB(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_aeb, \
.get = snd_hdsp_get_aeb, \
.put = snd_hdsp_put_aeb \
}
static int hdsp_aeb(struct hdsp *hdsp)
{
if (hdsp->control_register & HDSP_AnalogExtensionBoard)
return 1;
return 0;
}
static int hdsp_set_aeb(struct hdsp *hdsp, int mode)
{
if (mode)
hdsp->control_register |= HDSP_AnalogExtensionBoard;
else
hdsp->control_register &= ~HDSP_AnalogExtensionBoard;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_aeb snd_ctl_boolean_mono_info
static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp);
return 0;
}
static int snd_hdsp_put_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_aeb(hdsp);
hdsp_set_aeb(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_PREF_SYNC_REF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@ -2747,58 +2558,6 @@ static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_c
return 0;
}
#define HDSP_LINE_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_line_out, \
.get = snd_hdsp_get_line_out, \
.put = snd_hdsp_put_line_out \
}
static int hdsp_line_out(struct hdsp *hdsp)
{
return (hdsp->control_register & HDSP_LineOut) ? 1 : 0;
}
static int hdsp_set_line_output(struct hdsp *hdsp, int out)
{
if (out)
hdsp->control_register |= HDSP_LineOut;
else
hdsp->control_register &= ~HDSP_LineOut;
hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
return 0;
}
#define snd_hdsp_info_line_out snd_ctl_boolean_mono_info
static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
spin_lock_irq(&hdsp->lock);
ucontrol->value.integer.value[0] = hdsp_line_out(hdsp);
spin_unlock_irq(&hdsp->lock);
return 0;
}
static int snd_hdsp_put_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
int change;
unsigned int val;
if (!snd_hdsp_use_is_exclusive(hdsp))
return -EBUSY;
val = ucontrol->value.integer.value[0] & 1;
spin_lock_irq(&hdsp->lock);
change = (int)val != hdsp_line_out(hdsp);
hdsp_set_line_output(hdsp, val);
spin_unlock_irq(&hdsp->lock);
return change;
}
#define HDSP_PRECISE_POINTER(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
.name = xname, \
@ -3190,7 +2949,7 @@ static struct snd_kcontrol_new snd_hdsp_9632_controls[] = {
HDSP_DA_GAIN("DA Gain", 0),
HDSP_AD_GAIN("AD Gain", 0),
HDSP_PHONE_GAIN("Phones Gain", 0),
HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0),
HDSP_TOGGLE_SETTING("XLR Breakout Cable", HDSP_XLRBreakoutCable),
HDSP_DDS_OFFSET("DDS Sample Rate Offset", 0)
};
@ -3232,10 +2991,10 @@ static struct snd_kcontrol_new snd_hdsp_controls[] = {
},
HDSP_MIXER("Mixer", 0),
HDSP_SPDIF_IN("IEC958 Input Connector", 0),
HDSP_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
HDSP_SPDIF_PROFESSIONAL("IEC958 Professional Bit", 0),
HDSP_SPDIF_EMPHASIS("IEC958 Emphasis Bit", 0),
HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
HDSP_TOGGLE_SETTING("IEC958 Output also on ADAT1", HDSP_SPDIFOpticalOut),
HDSP_TOGGLE_SETTING("IEC958 Professional Bit", HDSP_SPDIFProfessional),
HDSP_TOGGLE_SETTING("IEC958 Emphasis Bit", HDSP_SPDIFEmphasis),
HDSP_TOGGLE_SETTING("IEC958 Non-audio Bit", HDSP_SPDIFNonAudio),
/* 'Sample Clock Source' complies with the alsa control naming scheme */
HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
{
@ -3255,7 +3014,7 @@ HDSP_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
HDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0),
HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0),
HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0),
HDSP_LINE_OUT("Line Out", 0),
HDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut),
HDSP_PRECISE_POINTER("Precise Pointer", 0),
HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
};
@ -3572,7 +3331,9 @@ static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
HDSP_MIXER("Mixer", 0)
};
static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0);
static struct snd_kcontrol_new snd_hdsp_96xx_aeb =
HDSP_TOGGLE_SETTING("Analog Extension Board",
HDSP_AnalogExtensionBoard);
static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
@ -3995,7 +3756,9 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
}
snd_iprintf(buffer, "Phones Gain : %s\n", tmp);
snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no");
snd_iprintf(buffer, "XLR Breakout Cable : %s\n",
hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ?
"yes" : "no");
if (hdsp->control_register & HDSP_AnalogExtensionBoard)
snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n");
@ -5026,29 +4789,38 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp);
info.spdif_professional = (unsigned char)hdsp_spdif_professional(hdsp);
info.spdif_emphasis = (unsigned char)hdsp_spdif_emphasis(hdsp);
info.spdif_nonaudio = (unsigned char)hdsp_spdif_nonaudio(hdsp);
info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp,
HDSP_SPDIFOpticalOut);
info.spdif_professional = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional);
info.spdif_emphasis = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis);
info.spdif_nonaudio = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio);
info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp);
info.system_sample_rate = hdsp->system_sample_rate;
info.autosync_sample_rate = hdsp_external_sample_rate(hdsp);
info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp);
info.clock_source = (unsigned char)hdsp_clock_source(hdsp);
info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp);
info.line_out = (unsigned char)hdsp_line_out(hdsp);
info.line_out = (unsigned char)
hdsp_toggle_setting(hdsp, HDSP_LineOut);
if (hdsp->io_type == H9632) {
info.da_gain = (unsigned char)hdsp_da_gain(hdsp);
info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp);
info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp);
info.xlr_breakout_cable =
(unsigned char)hdsp_toggle_setting(hdsp,
HDSP_XLRBreakoutCable);
} else if (hdsp->io_type == RPM) {
info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
}
if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp);
info.analog_extension_board =
(unsigned char)hdsp_toggle_setting(hdsp,
HDSP_AnalogExtensionBoard);
spin_unlock_irqrestore(&hdsp->lock, flags);
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;

View File

@ -2517,7 +2517,7 @@ static int check_dxs_list(struct pci_dev *pci, int revision)
w = snd_pci_quirk_lookup(pci, dxs_whitelist);
if (w) {
snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n",
w->name);
snd_pci_quirk_name(w));
return w->value;
}

View File

@ -1,6 +1,6 @@
config SND_ATMEL_SOC
tristate "SoC Audio for the Atmel System-on-Chip"
depends on ARCH_AT91
depends on HAS_IOMEM
help
Say Y or M if you want to add support for codecs attached to
the ATMEL SSC interface. You will also need
@ -24,7 +24,7 @@ config SND_ATMEL_SOC_SSC
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
@ -34,7 +34,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
config SND_AT91_SOC_AFEB9260
tristate "SoC Audio support for AFEB9260 board"
depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_TLV320AIC23

View File

@ -159,7 +159,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
pr_debug("atmel-pcm: "
"hw_params: DMA for %s initialized "
"(dma_bytes=%u, period_size=%u)\n",
"(dma_bytes=%zu, period_size=%zu)\n",
prtd->params->name,
runtime->dma_bytes,
prtd->period_size);
@ -201,7 +201,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
int ret = 0;
pr_debug("atmel-pcm:buffer_size = %ld,"
"dma_area = %p, dma_bytes = %u\n",
"dma_area = %p, dma_bytes = %zu\n",
rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
switch (cmd) {

View File

@ -49,7 +49,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
buf->private_data = NULL;
buf->area = dma_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n",
pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
(void *)buf->area, (void *)buf->addr, size);
if (!buf->area)

View File

@ -88,7 +88,8 @@ void atmel_pcm_free(struct snd_pcm *pcm);
int atmel_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma);
#ifdef CONFIG_SND_ATMEL_SOC_PDC
#if defined(CONFIG_SND_ATMEL_SOC_PDC) || \
defined(CONFIG_SND_ATMEL_SOC_PDC_MODULE)
int atmel_pcm_pdc_platform_register(struct device *dev);
void atmel_pcm_pdc_platform_unregister(struct device *dev);
#else
@ -101,7 +102,8 @@ static inline void atmel_pcm_pdc_platform_unregister(struct device *dev)
}
#endif
#ifdef CONFIG_SND_ATMEL_SOC_DMA
#if defined(CONFIG_SND_ATMEL_SOC_DMA) || \
defined(CONFIG_SND_ATMEL_SOC_DMA_MODULE)
int atmel_pcm_dma_platform_register(struct device *dev);
void atmel_pcm_dma_platform_unregister(struct device *dev);
#else

View File

@ -42,8 +42,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <mach/hardware.h>
#include "atmel-pcm.h"
#include "atmel_ssc_dai.h"
@ -679,15 +677,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
# define atmel_ssc_resume NULL
#endif /* CONFIG_PM */
static int atmel_ssc_probe(struct snd_soc_dai *dai)
{
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
snd_soc_dai_set_drvdata(dai, ssc_p);
return 0;
}
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
@ -703,7 +692,6 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
};
static struct snd_soc_dai_driver atmel_ssc_dai = {
.probe = atmel_ssc_probe,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@ -790,8 +778,8 @@ void atmel_ssc_put_audio(int ssc_id)
{
struct ssc_device *ssc = ssc_info[ssc_id].ssc;
ssc_free(ssc);
asoc_ssc_exit(&ssc->pdev->dev);
ssc_free(ssc);
}
EXPORT_SYMBOL_GPL(atmel_ssc_put_audio);

View File

@ -305,10 +305,10 @@ static int at91sam9g20ek_audio_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
atmel_ssc_put_audio(0);
snd_soc_unregister_card(card);
clk_put(mclk);
clk_disable(mclk);
mclk = NULL;
snd_soc_unregister_card(card);
atmel_ssc_put_audio(0);
return 0;
}

View File

@ -36,6 +36,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
select SND_SOC_CX20442
select SND_SOC_DA7210 if I2C
select SND_SOC_DA7213 if I2C
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
select SND_SOC_DFBMCS320
@ -98,7 +99,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8782
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8900 if I2C
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8903 if I2C && GENERIC_HARDIRQS
select SND_SOC_WM8904 if I2C
select SND_SOC_WM8940 if I2C
select SND_SOC_WM8955 if I2C
@ -247,6 +248,9 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
config SND_SOC_DA7213
tristate
config SND_SOC_DA732X
tristate

View File

@ -23,6 +23,7 @@ snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
snd-soc-dfbmcs320-objs := dfbmcs320.o
@ -147,6 +148,7 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o

View File

@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <sound/soc.h>
#include <sound/initval.h>
@ -513,12 +514,31 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4648 = {
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static struct of_device_id ak4642_of_match[];
static int ak4642_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct device_node *np = i2c->dev.of_node;
const struct snd_soc_codec_driver *driver;
driver = NULL;
if (np) {
const struct of_device_id *of_id;
of_id = of_match_device(ak4642_of_match, &i2c->dev);
if (of_id)
driver = of_id->data;
} else {
driver = (struct snd_soc_codec_driver *)id->driver_data;
}
if (!driver) {
dev_err(&i2c->dev, "no driver\n");
return -EINVAL;
}
return snd_soc_register_codec(&i2c->dev,
(struct snd_soc_codec_driver *)id->driver_data,
&ak4642_dai, 1);
driver, &ak4642_dai, 1);
}
static int ak4642_i2c_remove(struct i2c_client *client)
@ -527,6 +547,14 @@ static int ak4642_i2c_remove(struct i2c_client *client)
return 0;
}
static struct of_device_id ak4642_of_match[] = {
{ .compatible = "asahi-kasei,ak4642", .data = &soc_codec_dev_ak4642},
{ .compatible = "asahi-kasei,ak4643", .data = &soc_codec_dev_ak4642},
{ .compatible = "asahi-kasei,ak4648", .data = &soc_codec_dev_ak4648},
{},
};
MODULE_DEVICE_TABLE(of, ak4642_of_match);
static const struct i2c_device_id ak4642_i2c_id[] = {
{ "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 },
{ "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 },
@ -539,6 +567,7 @@ static struct i2c_driver ak4642_i2c_driver = {
.driver = {
.name = "ak4642-codec",
.owner = THIS_MODULE,
.of_match_table = ak4642_of_match,
},
.probe = ak4642_i2c_probe,
.remove = ak4642_i2c_remove,

View File

@ -56,14 +56,14 @@
#define arizona_fll_warn(_fll, fmt, ...) \
dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_dbg(_fll, fmt, ...) \
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_aif_err(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_warn(_dai, fmt, ...) \
dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_dbg(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
@ -141,6 +141,30 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"ASRC1R",
"ASRC2L",
"ASRC2R",
"ISRC1INT1",
"ISRC1INT2",
"ISRC1INT3",
"ISRC1INT4",
"ISRC1DEC1",
"ISRC1DEC2",
"ISRC1DEC3",
"ISRC1DEC4",
"ISRC2INT1",
"ISRC2INT2",
"ISRC2INT3",
"ISRC2INT4",
"ISRC2DEC1",
"ISRC2DEC2",
"ISRC2DEC3",
"ISRC2DEC4",
"ISRC3INT1",
"ISRC3INT2",
"ISRC3INT3",
"ISRC3INT4",
"ISRC3DEC1",
"ISRC3DEC2",
"ISRC3DEC3",
"ISRC3DEC4",
};
EXPORT_SYMBOL_GPL(arizona_mixer_texts);
@ -220,6 +244,30 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x91,
0x92,
0x93,
0xa0, /* ISRC1INT1 */
0xa1,
0xa2,
0xa3,
0xa4, /* ISRC1DEC1 */
0xa5,
0xa6,
0xa7,
0xa8, /* ISRC2DEC1 */
0xa9,
0xaa,
0xab,
0xac, /* ISRC2INT1 */
0xad,
0xae,
0xaf,
0xb0, /* ISRC3DEC1 */
0xb1,
0xb2,
0xb3,
0xb4, /* ISRC3INT1 */
0xb5,
0xb6,
0xb7,
};
EXPORT_SYMBOL_GPL(arizona_mixer_values);
@ -275,9 +323,35 @@ const struct soc_enum arizona_lhpf4_mode =
arizona_lhpf_mode_text);
EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
static const char *arizona_ng_hold_text[] = {
"30ms", "120ms", "250ms", "500ms",
};
const struct soc_enum arizona_ng_hold =
SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
4, arizona_ng_hold_text);
EXPORT_SYMBOL_GPL(arizona_ng_hold);
int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
int event)
{
unsigned int reg;
if (w->shift % 2)
reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
else
reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
ARIZONA_IN1L_MUTE);
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_in_ev);
@ -417,6 +491,10 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
case 147456000:
val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
break;
case 0:
dev_dbg(arizona->dev, "%s cleared\n", name);
*clk = freq;
return 0;
default:
return -EINVAL;
}
@ -635,6 +713,9 @@ static int arizona_startup(struct snd_pcm_substream *substream,
return 0;
}
if (base_rate == 0)
return 0;
if (base_rate % 8000)
constraint = &arizona_44k1_constraint;
else
@ -645,25 +726,81 @@ static int arizona_startup(struct snd_pcm_substream *substream,
constraint);
}
static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
int base = dai->driver->base;
int i, sr_val;
/*
* We will need to be more flexible than this in future,
* currently we use a single sample rate for SYSCLK.
*/
for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
if (arizona_sr_vals[i] == params_rate(params))
break;
if (i == ARRAY_SIZE(arizona_sr_vals)) {
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
params_rate(params));
return -EINVAL;
}
sr_val = i;
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
if (base)
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 0);
break;
case ARIZONA_CLK_ASYNCCLK:
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
if (base)
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK,
8 << ARIZONA_AIF1_RATE_SHIFT);
break;
default:
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
return -EINVAL;
}
return 0;
}
static int arizona_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
struct arizona *arizona = priv->arizona;
int base = dai->driver->base;
const int *rates;
int i;
int bclk, lrclk, wl, frame, sr_val;
int i, ret;
int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
int bclk, lrclk, wl, frame, bclk_target;
if (params_rate(params) % 8000)
rates = &arizona_44k1_bclk_rates[0];
else
rates = &arizona_48k_bclk_rates[0];
bclk_target = snd_soc_params_to_bclk(params);
if (chan_limit && chan_limit < params_channels(params)) {
arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
bclk_target /= params_channels(params);
bclk_target *= chan_limit;
}
for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
if (rates[i] >= snd_soc_params_to_bclk(params) &&
if (rates[i] >= bclk_target &&
rates[i] % params_rate(params) == 0) {
bclk = i;
break;
@ -675,16 +812,6 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
if (arizona_sr_vals[i] == params_rate(params))
break;
if (i == ARRAY_SIZE(arizona_sr_vals)) {
arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
params_rate(params));
return -EINVAL;
}
sr_val = i;
lrclk = rates[bclk] / params_rate(params);
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
@ -693,28 +820,9 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
wl = snd_pcm_format_width(params_format(params));
frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
/*
* We will need to be more flexible than this in future,
* currently we use a single sample rate for SYSCLK.
*/
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK, 0);
break;
case ARIZONA_CLK_ASYNCCLK:
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_RATE_MASK,
8 << ARIZONA_AIF1_RATE_SHIFT);
break;
default:
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
return -EINVAL;
}
ret = arizona_hw_params_rate(substream, params, dai);
if (ret != 0)
return ret;
snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
@ -789,11 +897,27 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
return snd_soc_dapm_sync(&codec->dapm);
}
static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_codec *codec = dai->codec;
int base = dai->driver->base;
unsigned int reg;
if (tristate)
reg = ARIZONA_AIF1_TRI;
else
reg = 0;
return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
ARIZONA_AIF1_TRI, reg);
}
const struct snd_soc_dai_ops arizona_dai_ops = {
.startup = arizona_startup,
.set_fmt = arizona_set_fmt,
.hw_params = arizona_hw_params,
.set_sysclk = arizona_dai_set_sysclk,
.set_tristate = arizona_set_tristate,
};
EXPORT_SYMBOL_GPL(arizona_dai_ops);
@ -807,17 +931,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id)
}
EXPORT_SYMBOL_GPL(arizona_init_dai);
static irqreturn_t arizona_fll_lock(int irq, void *data)
{
struct arizona_fll *fll = data;
arizona_fll_dbg(fll, "Lock status changed\n");
complete(&fll->lock);
return IRQ_HANDLED;
}
static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
{
struct arizona_fll *fll = data;
@ -910,7 +1023,7 @@ static int arizona_calc_fll(struct arizona_fll *fll,
cfg->n = target / (ratio * Fref);
if (target % Fref) {
if (target % (ratio * Fref)) {
gcd_fll = gcd(target, ratio * Fref);
arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
@ -922,6 +1035,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
cfg->lambda = 0;
}
/* Round down to 16bit range with cost of accuracy lost.
* Denominator must be bigger than numerator so we only
* take care of it.
*/
while (cfg->lambda >= (1 << 16)) {
cfg->theta >>= 1;
cfg->lambda >>= 1;
}
arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
cfg->n, cfg->theta, cfg->lambda);
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
@ -1057,7 +1179,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
{
int ret;
init_completion(&fll->lock);
init_completion(&fll->ok);
fll->id = id;
@ -1068,13 +1189,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
"FLL%d clock OK", id);
ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
arizona_fll_lock, fll);
if (ret != 0) {
dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
id, ret);
}
ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
arizona_fll_clock_ok, fll);
if (ret != 0) {
@ -1089,6 +1203,40 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
}
EXPORT_SYMBOL_GPL(arizona_init_fll);
/**
* arizona_set_output_mode - Set the mode of the specified output
*
* @codec: Device to configure
* @output: Output number
* @diff: True to set the output to differential mode
*
* Some systems use external analogue switches to connect more
* analogue devices to the CODEC than are supported by the device. In
* some systems this requires changing the switched output from single
* ended to differential mode dynamically at runtime, an operation
* supported using this function.
*
* Most systems have a single static configuration and should use
* platform data instead.
*/
int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
{
unsigned int reg, val;
if (output < 1 || output > 6)
return -EINVAL;
reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
if (diff)
val = ARIZONA_OUT1_MONO;
else
val = 0;
return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
}
EXPORT_SYMBOL_GPL(arizona_set_output_mode);
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");

View File

@ -66,7 +66,7 @@ struct arizona_priv {
struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
};
#define ARIZONA_NUM_MIXER_INPUTS 75
#define ARIZONA_NUM_MIXER_INPUTS 99
extern const unsigned int arizona_mixer_tlv[];
extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
@ -176,6 +176,8 @@ extern const struct soc_enum arizona_lhpf2_mode;
extern const struct soc_enum arizona_lhpf3_mode;
extern const struct soc_enum arizona_lhpf4_mode;
extern const struct soc_enum arizona_ng_hold;
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
@ -195,7 +197,6 @@ struct arizona_fll {
int id;
unsigned int base;
unsigned int vco_mult;
struct completion lock;
struct completion ok;
unsigned int fref;
unsigned int fout;
@ -211,4 +212,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source,
extern int arizona_init_dai(struct arizona_priv *priv, int dai);
int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
bool diff);
#endif

View File

@ -167,6 +167,8 @@ struct cs4271_private {
int gpio_nreset;
/* GPIO that disable serial bus, if any */
int gpio_disable;
/* enable soft reset workaround */
bool enable_soft_reset;
};
/*
@ -325,6 +327,33 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
int i, ret;
unsigned int ratio, val;
if (cs4271->enable_soft_reset) {
/*
* Put the codec in soft reset and back again in case it's not
* currently streaming data. This way of bringing the codec in
* sync to the current clocks is not explicitly documented in
* the data sheet, but it seems to work fine, and in contrast
* to a read hardware reset, we don't have to sync back all
* registers every time.
*/
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
!dai->capture_active) ||
(substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
!dai->playback_active)) {
ret = snd_soc_update_bits(codec, CS4271_MODE2,
CS4271_MODE2_PDN,
CS4271_MODE2_PDN);
if (ret < 0)
return ret;
ret = snd_soc_update_bits(codec, CS4271_MODE2,
CS4271_MODE2_PDN, 0);
if (ret < 0)
return ret;
}
}
cs4271->rate = params_rate(params);
/* Configure DAC */
@ -484,6 +513,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)
if (of_get_property(codec->dev->of_node,
"cirrus,amutec-eq-bmutec", NULL))
amutec_eq_bmutec = true;
if (of_get_property(codec->dev->of_node,
"cirrus,enable-soft-reset", NULL))
cs4271->enable_soft_reset = true;
}
#endif
@ -492,6 +525,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
gpio_nreset = cs4271plat->gpio_nreset;
amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
}
if (gpio_nreset >= 0)

Some files were not shown because too many files have changed in this diff Show More