]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'for-next' into topic/hda-core
authorTakashi Iwai <tiwai@suse.de>
Mon, 23 Mar 2015 12:14:02 +0000 (13:14 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 23 Mar 2015 12:14:02 +0000 (13:14 +0100)
166 files changed:
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
Documentation/sound/alsa/HD-Audio.txt
Documentation/sound/alsa/timestamping.txt [new file with mode: 0644]
include/sound/compress_driver.h
include/sound/control.h
include/sound/core.h
include/sound/pcm.h
include/sound/pcm_params.h
include/sound/seq_device.h
include/sound/seq_kernel.h
include/sound/soc.h
include/uapi/sound/asequencer.h
include/uapi/sound/asound.h
include/uapi/sound/compress_offload.h
include/uapi/sound/emu10k1.h
include/uapi/sound/hdspm.h
sound/aoa/soundbus/i2sbus/core.c
sound/core/control.c
sound/core/device.c
sound/core/hwdep.c
sound/core/init.c
sound/core/oss/mixer_oss.c
sound/core/oss/pcm_oss.c
sound/core/pcm.c
sound/core/pcm_compat.c
sound/core/pcm_dmaengine.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/seq/oss/seq_oss.c
sound/core/seq/oss/seq_oss_init.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/oss/seq_oss_readq.c
sound/core/seq/oss/seq_oss_synth.c
sound/core/seq/oss/seq_oss_synth.h
sound/core/seq/seq_device.c
sound/core/seq/seq_dummy.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_prioq.c
sound/core/seq/seq_queue.c
sound/core/seq/seq_timer.c
sound/core/sound.c
sound/core/timer.c
sound/drivers/opl3/opl3_seq.c
sound/drivers/opl4/opl4_seq.c
sound/firewire/amdtp.c
sound/firewire/fireworks/fireworks_transaction.c
sound/isa/sb/emu8000_synth.c
sound/oss/opl3.c
sound/oss/sb_ess.c
sound/oss/sb_midi.c
sound/oss/sys_timer.c
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/azt3328.c
sound/pci/cmipci.c
sound/pci/emu10k1/emu10k1_synth.c
sound/pci/hda/Makefile
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_beep.h
sound/pci/hda/hda_bind.c [new file with mode: 0644]
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_i915.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.h
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_priv.h [deleted file]
sound/pci/hda/hda_proc.c
sound/pci/hda/hda_sysfs.c
sound/pci/hda/hda_tegra.c
sound/pci/hda/hda_trace.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/wtm.c
sound/pci/rme9652/hdspm.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_ssc_dai.h
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau1977.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs4265.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5670.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h
sound/soc/codecs/sn95031.c
sound/soc/codecs/sn95031.h
sound/soc/codecs/sta350.c
sound/soc/codecs/tas2552.c
sound/soc/codecs/wm8804-i2c.c [new file with mode: 0644]
sound/soc/codecs/wm8804-spi.c [new file with mode: 0644]
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8804.h
sound/soc/codecs/wm_adsp.c
sound/soc/davinci/Kconfig
sound/soc/davinci/Makefile
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-pcm.c [deleted file]
sound/soc/davinci/davinci-pcm.h [deleted file]
sound/soc/davinci/davinci-vcif.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/imx-es8328.c
sound/soc/fsl/wm1133-ev1.c
sound/soc/generic/simple-card.c
sound/soc/intel/broadwell.c
sound/soc/intel/byt-max98090.c
sound/soc/intel/bytcr_dpcm_rt5640.c
sound/soc/intel/cht_bsw_rt5645.c
sound/soc/intel/cht_bsw_rt5672.c
sound/soc/intel/haswell.c
sound/soc/intel/mfld_machine.c
sound/soc/intel/sst-mfld-platform-pcm.c
sound/soc/intel/sst-mfld-platform.h
sound/soc/intel/sst/sst.c
sound/soc/intel/sst/sst.h
sound/soc/intel/sst/sst_drv_interface.c
sound/soc/intel/sst/sst_loader.c
sound/soc/omap/Kconfig
sound/soc/omap/ams-delta.c
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-twl4030.c
sound/soc/omap/rx51.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/ttc-dkb.c
sound/soc/pxa/z2.c
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/littlemill.c
sound/soc/samsung/lowland.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/speyside.c
sound/soc/samsung/tobermory.c
sound/soc/soc-core.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_max98090.c
sound/soc/tegra/tegra_rt5640.c
sound/soc/tegra/tegra_rt5677.c
sound/soc/tegra/tegra_wm8903.c
sound/usb/quirks.c

index c949abc2992f5fd1d8c2e1fcb2eb5a75521037a6..c3495beba35841773cd1ec0c7d3efe1d952d22c4 100644 (file)
@@ -18,6 +18,7 @@ Required properties:
   * Headphones
   * Speakers
   * Mic Jack
+  * Int Mic
 
 - nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
   connected to the CODEC.
index 42a0a39b77e6a5da339e0f71717a6d3809986c24..e7193aac669c3a7afc356276c167de3f887fc027 100644 (file)
@@ -466,7 +466,11 @@ The generic parser supports the following hints:
 - add_jack_modes (bool): add "xxx Jack Mode" enum controls to each
   I/O jack for allowing to change the headphone amp and mic bias VREF
   capabilities
-- power_down_unused (bool): power down the unused widgets
+- power_save_node (bool): advanced power management for each widget,
+  controlling the power sate (D0/D3) of each widget node depending on
+  the actual pin and stream states
+- power_down_unused (bool): power down the unused widgets, a subset of
+  power_save_node, and will be dropped in future
 - add_hp_mic (bool): add the headphone to capture source if possible
 - hp_mic_detect (bool): enable/disable the hp/mic shared input for a
   single built-in mic case; default true
diff --git a/Documentation/sound/alsa/timestamping.txt b/Documentation/sound/alsa/timestamping.txt
new file mode 100644 (file)
index 0000000..0b191a2
--- /dev/null
@@ -0,0 +1,200 @@
+The ALSA API can provide two different system timestamps:
+
+- Trigger_tstamp is the system time snapshot taken when the .trigger
+callback is invoked. This snapshot is taken by the ALSA core in the
+general case, but specific hardware may have synchronization
+capabilities or conversely may only be able to provide a correct
+estimate with a delay. In the latter two cases, the low-level driver
+is responsible for updating the trigger_tstamp at the most appropriate
+and precise moment. Applications should not rely solely on the first
+trigger_tstamp but update their internal calculations if the driver
+provides a refined estimate with a delay.
+
+- tstamp is the current system timestamp updated during the last
+event or application query.
+The difference (tstamp - trigger_tstamp) defines the elapsed time.
+
+The ALSA API provides reports two basic pieces of information, avail
+and delay, which combined with the trigger and current system
+timestamps allow for applications to keep track of the 'fullness' of
+the ring buffer and the amount of queued samples.
+
+The use of these different pointers and time information depends on
+the application needs:
+
+- 'avail' reports how much can be written in the ring buffer
+- 'delay' reports the time it will take to hear a new sample after all
+queued samples have been played out.
+
+When timestamps are enabled, the avail/delay information is reported
+along with a snapshot of system time. Applications can select from
+CLOCK_REALTIME (NTP corrections including going backwards),
+CLOCK_MONOTONIC (NTP corrections but never going backwards),
+CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode
+dynamically with sw_params
+
+
+The ALSA API also provide an audio_tstamp which reflects the passage
+of time as measured by different components of audio hardware.  In
+ascii-art, this could be represented as follows (for the playback
+case):
+
+
+--------------------------------------------------------------> time
+  ^               ^              ^                ^           ^
+  |               |              |                |           |
+ analog         link            dma              app       FullBuffer
+ time           time           time              time        time
+  |               |              |                |           |
+  |< codec delay >|<--hw delay-->|<queued samples>|<---avail->|
+  |<----------------- delay---------------------->|           |
+                                |<----ring buffer length---->|
+
+The analog time is taken at the last stage of the playback, as close
+as possible to the actual transducer
+
+The link time is taken at the output of the SOC/chipset as the samples
+are pushed on a link. The link time can be directly measured if
+supported in hardware by sample counters or wallclocks (e.g. with
+HDAudio 24MHz or PTP clock for networked solutions) or indirectly
+estimated (e.g. with the frame counter in USB).
+
+The DMA time is measured using counters - typically the least reliable
+of all measurements due to the bursty natured of DMA transfers.
+
+The app time corresponds to the time tracked by an application after
+writing in the ring buffer.
+
+The application can query what the hardware supports, define which
+audio time it wants reported by selecting the relevant settings in
+audio_tstamp_config fields, get an estimate of the timestamp
+accuracy. It can also request the delay-to-analog be included in the
+measurement. Direct access to the link time is very interesting on
+platforms that provide an embedded DSP; measuring directly the link
+time with dedicated hardware, possibly synchronized with system time,
+removes the need to keep track of internal DSP processing times and
+latency.
+
+In case the application requests an audio tstamp that is not supported
+in hardware/low-level driver, the type is overridden as DEFAULT and the
+timestamp will report the DMA time based on the hw_pointer value.
+
+For backwards compatibility with previous implementations that did not
+provide timestamp selection, with a zero-valued COMPAT timestamp type
+the results will default to the HDAudio wall clock for playback
+streams and to the DMA time (hw_ptr) in all other cases.
+
+The audio timestamp accuracy can be returned to user-space, so that
+appropriate decisions are made:
+
+- for dma time (default), the granularity of the transfers can be
+  inferred from the steps between updates and in turn provide
+  information on how much the application pointer can be rewound
+  safely.
+
+- the link time can be used to track long-term drifts between audio
+  and system time using the (tstamp-trigger_tstamp)/audio_tstamp
+  ratio, the precision helps define how much smoothing/low-pass
+  filtering is required. The link time can be either reset on startup
+  or reported as is (the latter being useful to compare progress of
+  different streams - but may require the wallclock to be always
+  running and not wrap-around during idle periods). If supported in
+  hardware, the absolute link time could also be used to define a
+  precise start time (patches WIP)
+
+- including the delay in the audio timestamp may
+  counter-intuitively not increase the precision of timestamps, e.g. if a
+  codec includes variable-latency DSP processing or a chain of
+  hardware components the delay is typically not known with precision.
+
+The accuracy is reported in nanosecond units (using an unsigned 32-bit
+word), which gives a max precision of 4.29s, more than enough for
+audio applications...
+
+Due to the varied nature of timestamping needs, even for a single
+application, the audio_tstamp_config can be changed dynamically. In
+the STATUS ioctl, the parameters are read-only and do not allow for
+any application selection. To work around this limitation without
+impacting legacy applications, a new STATUS_EXT ioctl is introduced
+with read/write parameters. ALSA-lib will be modified to make use of
+STATUS_EXT and effectively deprecate STATUS.
+
+The ALSA API only allows for a single audio timestamp to be reported
+at a time. This is a conscious design decision, reading the audio
+timestamps from hardware registers or from IPC takes time, the more
+timestamps are read the more imprecise the combined measurements
+are. To avoid any interpretation issues, a single (system, audio)
+timestamp is reported. Applications that need different timestamps
+will be required to issue multiple queries and perform an
+interpolation of the results
+
+In some hardware-specific configuration, the system timestamp is
+latched by a low-level audio subsytem, and the information provided
+back to the driver. Due to potential delays in the communication with
+the hardware, there is a risk of misalignment with the avail and delay
+information. To make sure applications are not confused, a
+driver_timestamp field is added in the snd_pcm_status structure; this
+timestamp shows when the information is put together by the driver
+before returning from the STATUS and STATUS_EXT ioctl. in most cases
+this driver_timestamp will be identical to the regular system tstamp.
+
+Examples of typestamping with HDaudio:
+
+1. DMA timestamp, no compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=1
+playback: systime: 341121338 nsec, audio time 342000000 nsec,  systime delta -878662
+playback: systime: 426236663 nsec, audio time 427187500 nsec,  systime delta -950837
+playback: systime: 597080580 nsec, audio time 598000000 nsec,  systime delta -919420
+playback: systime: 682059782 nsec, audio time 683020833 nsec,  systime delta -961051
+playback: systime: 852896415 nsec, audio time 853854166 nsec,  systime delta -957751
+playback: systime: 937903344 nsec, audio time 938854166 nsec,  systime delta -950822
+
+2. DMA timestamp, compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=1 -d
+playback: systime: 341053347 nsec, audio time 341062500 nsec,  systime delta -9153
+playback: systime: 426072447 nsec, audio time 426062500 nsec,  systime delta 9947
+playback: systime: 596899518 nsec, audio time 596895833 nsec,  systime delta 3685
+playback: systime: 681915317 nsec, audio time 681916666 nsec,  systime delta -1349
+playback: systime: 852741306 nsec, audio time 852750000 nsec,  systime delta -8694
+
+3. link timestamp, compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=2 -d
+playback: systime: 341060004 nsec, audio time 341062791 nsec,  systime delta -2787
+playback: systime: 426242074 nsec, audio time 426244875 nsec,  systime delta -2801
+playback: systime: 597080992 nsec, audio time 597084583 nsec,  systime delta -3591
+playback: systime: 682084512 nsec, audio time 682088291 nsec,  systime delta -3779
+playback: systime: 852936229 nsec, audio time 852940916 nsec,  systime delta -4687
+playback: systime: 938107562 nsec, audio time 938112708 nsec,  systime delta -5146
+
+Example 1 shows that the timestamp at the DMA level is close to 1ms
+ahead of the actual playback time (as a side time this sort of
+measurement can help define rewind safeguards). Compensating for the
+DMA-link delay in example 2 helps remove the hardware buffering abut
+the information is still very jittery, with up to one sample of
+error. In example 3 where the timestamps are measured with the link
+wallclock, the timestamps show a monotonic behavior and a lower
+dispersion.
+
+Example 3 and 4 are with USB audio class. Example 3 shows a high
+offset between audio time and system time due to buffering. Example 4
+shows how compensating for the delay exposes a 1ms accuracy (due to
+the use of the frame counter by the driver)
+
+Example 3: DMA timestamp, no compensation for delay, delta of ~5ms
+$ ./audio_time -p -Dhw:1 -t1
+playback: systime: 120174019 nsec, audio time 125000000 nsec,  systime delta -4825981
+playback: systime: 245041136 nsec, audio time 250000000 nsec,  systime delta -4958864
+playback: systime: 370106088 nsec, audio time 375000000 nsec,  systime delta -4893912
+playback: systime: 495040065 nsec, audio time 500000000 nsec,  systime delta -4959935
+playback: systime: 620038179 nsec, audio time 625000000 nsec,  systime delta -4961821
+playback: systime: 745087741 nsec, audio time 750000000 nsec,  systime delta -4912259
+playback: systime: 870037336 nsec, audio time 875000000 nsec,  systime delta -4962664
+
+Example 4: DMA timestamp, compensation for delay, delay of ~1ms
+$ ./audio_time -p -Dhw:1 -t1 -d
+playback: systime: 120190520 nsec, audio time 120000000 nsec,  systime delta 190520
+playback: systime: 245036740 nsec, audio time 244000000 nsec,  systime delta 1036740
+playback: systime: 370034081 nsec, audio time 369000000 nsec,  systime delta 1034081
+playback: systime: 495159907 nsec, audio time 494000000 nsec,  systime delta 1159907
+playback: systime: 620098824 nsec, audio time 619000000 nsec,  systime delta 1098824
+playback: systime: 745031847 nsec, audio time 744000000 nsec,  systime delta 1031847
index f48089d364c540a0527d6a874ca0e6516e5254b1..fa1d05512c0984a63a8b54e16d411fb2052c6f89 100644 (file)
@@ -70,7 +70,7 @@ struct snd_compr_runtime {
  * @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
+ * @next_track: has userspace signal next track transition, true when set
  * @private_data: pointer to DSP private data
  */
 struct snd_compr_stream {
@@ -95,7 +95,7 @@ struct snd_compr_stream {
  * and the stream properties
  * @get_params: retrieve the codec parameters, mandatory
  * @set_metadata: Set the metadata values for a stream
- * @get_metadata: retreives the requested metadata values from stream
+ * @get_metadata: retrieves the requested metadata values from stream
  * @trigger: Trigger operations like start, pause, resume, drain, stop.
  * This callback is mandatory
  * @pointer: Retrieve current h/w pointer information. Mandatory
index 75f3054023f71182b6cf4ab89491c65180cb6292..95aad6d3fd1a9b0765551d90719632baeea388b0 100644 (file)
@@ -227,7 +227,7 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
  * Add a virtual slave control to the given master.
  * Unlike snd_ctl_add_slave(), the element added via this function
  * is supposed to have volatile values, and get callback is called
- * at each time quried from the master.
+ * at each time queried from the master.
  *
  * When the control peeks the hardware values directly and the value
  * can be changed by other means than the put callback of the element,
index da5748289968074f2d89ae1c25e29f3a7298b789..b12931f513f4a89539e30ab825816571819e64bd 100644 (file)
@@ -278,7 +278,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
                   void *device_data, struct snd_device_ops *ops);
 int snd_device_register(struct snd_card *card, void *device_data);
 int snd_device_register_all(struct snd_card *card);
-int snd_device_disconnect_all(struct snd_card *card);
+void snd_device_disconnect(struct snd_card *card, void *device_data);
+void snd_device_disconnect_all(struct snd_card *card);
 void snd_device_free(struct snd_card *card, void *device_data);
 void snd_device_free_all(struct snd_card *card);
 
index c0ddb7e69c2863a385b34212b29255df993131e5..0cb7f3f5df7b9fca12f7233503f55f6b181470a7 100644 (file)
@@ -60,6 +60,9 @@ struct snd_pcm_hardware {
 
 struct snd_pcm_substream;
 
+struct snd_pcm_audio_tstamp_config; /* definitions further down */
+struct snd_pcm_audio_tstamp_report;
+
 struct snd_pcm_ops {
        int (*open)(struct snd_pcm_substream *substream);
        int (*close)(struct snd_pcm_substream *substream);
@@ -71,8 +74,10 @@ struct snd_pcm_ops {
        int (*prepare)(struct snd_pcm_substream *substream);
        int (*trigger)(struct snd_pcm_substream *substream, int cmd);
        snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
-       int (*wall_clock)(struct snd_pcm_substream *substream,
-                         struct timespec *audio_ts);
+       int (*get_time_info)(struct snd_pcm_substream *substream,
+                       struct timespec *system_ts, struct timespec *audio_ts,
+                       struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
+                       struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
        int (*copy)(struct snd_pcm_substream *substream, int channel,
                    snd_pcm_uframes_t pos,
                    void __user *buf, snd_pcm_uframes_t count);
@@ -281,6 +286,58 @@ struct snd_pcm_hw_constraint_ranges {
 
 struct snd_pcm_hwptr_log;
 
+/*
+ * userspace-provided audio timestamp config to kernel,
+ * structure is for internal use only and filled with dedicated unpack routine
+ */
+struct snd_pcm_audio_tstamp_config {
+       /* 5 of max 16 bits used */
+       u32 type_requested:4;
+       u32 report_delay:1; /* add total delay to A/D or D/A */
+};
+
+static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data,
+                                               struct snd_pcm_audio_tstamp_config *config)
+{
+       config->type_requested = data & 0xF;
+       config->report_delay = (data >> 4) & 1;
+}
+
+/*
+ * kernel-provided audio timestamp report to user-space
+ * structure is for internal use only and read by dedicated pack routine
+ */
+struct snd_pcm_audio_tstamp_report {
+       /* 6 of max 16 bits used for bit-fields */
+
+       /* for backwards compatibility */
+       u32 valid:1;
+
+       /* actual type if hardware could not support requested timestamp */
+       u32 actual_type:4;
+
+       /* accuracy represented in ns units */
+       u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */
+       u32 accuracy; /* up to 4.29s, will be packed in separate field  */
+};
+
+static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy,
+                                               const struct snd_pcm_audio_tstamp_report *report)
+{
+       u32 tmp;
+
+       tmp = report->accuracy_report;
+       tmp <<= 4;
+       tmp |= report->actual_type;
+       tmp <<= 1;
+       tmp |= report->valid;
+
+       *data &= 0xffff; /* zero-clear MSBs */
+       *data |= (tmp << 16);
+       *accuracy = report->accuracy;
+}
+
+
 struct snd_pcm_runtime {
        /* -- Status -- */
        struct snd_pcm_substream *trigger_master;
@@ -361,6 +418,11 @@ struct snd_pcm_runtime {
 
        struct snd_dma_buffer *dma_buffer_p;    /* allocated buffer */
 
+       /* -- audio timestamp config -- */
+       struct snd_pcm_audio_tstamp_config audio_tstamp_config;
+       struct snd_pcm_audio_tstamp_report audio_tstamp_report;
+       struct timespec driver_tstamp;
+
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        /* -- OSS things -- */
        struct snd_pcm_oss_runtime oss;
index 3c45f3924ba7e779a4d32a357665d0359abcbaaf..c704357775fc4ef077ef52fb27cfb97c75b378ee 100644 (file)
@@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p)
        return snd_pcm_format_physical_width(params_format(p));
 }
 
+static inline void
+params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
+{
+       snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT),
+               (__force int)fmt);
+}
+
 #endif /* __SOUND_PCM_PARAMS_H */
index 2b5f24cc75488844cc1e18183c0482298c653923..ddc0d504cf39b3009fe6e22fefab9d7e1da30b0a 100644 (file)
  * registered device information
  */
 
-#define ID_LEN 32
-
-/* status flag */
-#define SNDRV_SEQ_DEVICE_FREE          0
-#define SNDRV_SEQ_DEVICE_REGISTERED    1
-
 struct snd_seq_device {
        /* device info */
        struct snd_card *card;  /* sound card */
        int device;             /* device number */
-       char id[ID_LEN];        /* driver id */
+       const char *id;         /* driver id */
        char name[80];          /* device name */
        int argsize;            /* size of the argument */
        void *driver_data;      /* private data for driver */
-       int status;             /* flag - read only */
        void *private_data;     /* private data for the caller */
        void (*private_free)(struct snd_seq_device *device);
-       struct list_head list;  /* link to next device */
+       struct device dev;
 };
 
+#define to_seq_dev(_dev) \
+       container_of(_dev, struct snd_seq_device, dev)
+
+/* sequencer driver */
 
 /* driver operators
- * init_device:
+ * probe:
  *     Initialize the device with given parameters.
  *     Typically,
  *             1. call snd_hwdep_new
@@ -55,25 +52,40 @@ struct snd_seq_device {
  *             3. call snd_hwdep_register
  *             4. store the instance to dev->driver_data pointer.
  *             
- * free_device:
+ * remove:
  *     Release the private data.
  *     Typically, call snd_device_free(dev->card, dev->driver_data)
  */
-struct snd_seq_dev_ops {
-       int (*init_device)(struct snd_seq_device *dev);
-       int (*free_device)(struct snd_seq_device *dev);
+struct snd_seq_driver {
+       struct device_driver driver;
+       char *id;
+       int argsize;
 };
 
+#define to_seq_drv(_drv) \
+       container_of(_drv, struct snd_seq_driver, driver)
+
 /*
  * prototypes
  */
+#ifdef CONFIG_MODULES
 void snd_seq_device_load_drivers(void);
-int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result);
-int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize);
-int snd_seq_device_unregister_driver(char *id);
+#else
+#define snd_seq_device_load_drivers()
+#endif
+int snd_seq_device_new(struct snd_card *card, int device, const char *id,
+                      int argsize, struct snd_seq_device **result);
 
 #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device))
 
+int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv,
+                                          struct module *mod);
+#define snd_seq_driver_register(drv) \
+       __snd_seq_driver_register(drv, THIS_MODULE)
+void snd_seq_driver_unregister(struct snd_seq_driver *drv);
+
+#define module_snd_seq_driver(drv) \
+       module_driver(drv, snd_seq_driver_register, snd_seq_driver_unregister)
 
 /*
  * id strings for generic devices
index 18a2ac58b88f996d5668fef268f3f9c73256d1ce..feb58d45556064881bcddd8a1b403da13c6af358 100644 (file)
@@ -99,13 +99,9 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp,
 int snd_seq_event_port_detach(int client, int port);
 
 #ifdef CONFIG_MODULES
-void snd_seq_autoload_lock(void);
-void snd_seq_autoload_unlock(void);
 void snd_seq_autoload_init(void);
-#define snd_seq_autoload_exit()        snd_seq_autoload_lock()
+void snd_seq_autoload_exit(void);
 #else
-#define snd_seq_autoload_lock()
-#define snd_seq_autoload_unlock()
 #define snd_seq_autoload_init()
 #define snd_seq_autoload_exit()
 #endif
index 0d1ade19562857c7b65157636ac37b2f0222e202..b371aef9819f2adde194b39fecf72a035f6e03b4 100644 (file)
@@ -450,8 +450,10 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
                      struct snd_soc_dai *dai);
 
 /* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
-                    struct snd_soc_jack *jack);
+int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
+       struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
+       unsigned int num_pins);
+
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
                          struct snd_soc_jack_pin *pins);
@@ -659,7 +661,7 @@ struct snd_soc_jack_gpio {
 struct snd_soc_jack {
        struct mutex mutex;
        struct snd_jack *jack;
-       struct snd_soc_codec *codec;
+       struct snd_soc_card *card;
        struct list_head pins;
        int status;
        struct blocking_notifier_head notifier;
@@ -954,6 +956,9 @@ struct snd_soc_dai_link {
        unsigned int symmetric_channels:1;
        unsigned int symmetric_samplebits:1;
 
+       /* Mark this pcm with non atomic ops */
+       bool nonatomic;
+
        /* Do not create a PCM for this DAI link (Backend link) */
        unsigned int no_pcm:1;
 
@@ -1071,11 +1076,16 @@ struct snd_soc_card {
 
        /*
         * Card-specific routes and widgets.
+        * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
         */
        const struct snd_soc_dapm_widget *dapm_widgets;
        int num_dapm_widgets;
        const struct snd_soc_dapm_route *dapm_routes;
        int num_dapm_routes;
+       const struct snd_soc_dapm_widget *of_dapm_widgets;
+       int num_of_dapm_widgets;
+       const struct snd_soc_dapm_route *of_dapm_routes;
+       int num_of_dapm_routes;
        bool fully_routed;
 
        struct work_struct deferred_resume_work;
@@ -1469,7 +1479,7 @@ static inline struct snd_soc_codec *snd_soc_kcontrol_codec(
 }
 
 /**
- * snd_soc_kcontrol_platform() - Returns the platform that registerd the control
+ * snd_soc_kcontrol_platform() - Returns the platform that registered the control
  * @kcontrol: The control for which to get the platform
  *
  * Note: This function will only work correctly if the control has been
index 09c8a00ea503f77335e514eb8a8b53e5341b92f5..5a5fa4956ebd66f989f7e8886d77e09566127ac0 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef _UAPI__SOUND_ASEQUENCER_H
 #define _UAPI__SOUND_ASEQUENCER_H
 
+#include <sound/asound.h>
 
 /** version of the sequencer */
 #define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1)
index 0e88e7a0f0ebf227894f05ef6ed2225931b9d6d6..46145a5277fe0277808ad54e45ab7e1a3d7b9985 100644 (file)
@@ -25,6 +25,9 @@
 
 #include <linux/types.h>
 
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
 
 /*
  *  protocol version
@@ -140,7 +143,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 12)
+#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 13)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -267,10 +270,17 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_JOINT_DUPLEX    0x00200000      /* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START      0x00400000      /* pcm support some kind of sync go */
 #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP        0x00800000      /* period wakeup can be disabled */
-#define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* (Deprecated)has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_HAS_LINK_ATIME              0x01000000  /* report hardware link audio time, reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME     0x02000000  /* report absolute hardware link audio time, not reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
+#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
+
 #define SNDRV_PCM_INFO_DRAIN_TRIGGER   0x40000000              /* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES  0x80000000      /* internal kernel flag - FIFO size is in frames */
 
+
+
 typedef int __bitwise snd_pcm_state_t;
 #define        SNDRV_PCM_STATE_OPEN            ((__force snd_pcm_state_t) 0) /* stream is open */
 #define        SNDRV_PCM_STATE_SETUP           ((__force snd_pcm_state_t) 1) /* stream has a setup */
@@ -408,6 +418,22 @@ struct snd_pcm_channel_info {
        unsigned int step;              /* samples distance in bits */
 };
 
+enum {
+       /*
+        *  first definition for backwards compatibility only,
+        *  maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else
+        */
+       SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0,
+
+       /* timestamp definitions */
+       SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1,           /* DMA time, reported as per hw_ptr */
+       SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2,              /* link time reported by sample or wallclock counter, reset on startup */
+       SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3,     /* link time reported by sample or wallclock counter, not reset on startup */
+       SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4,    /* link time estimated indirectly */
+       SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */
+       SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
+};
+
 struct snd_pcm_status {
        snd_pcm_state_t state;          /* stream state */
        struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */
@@ -419,9 +445,11 @@ struct snd_pcm_status {
        snd_pcm_uframes_t avail_max;    /* max frames available on hw since last status */
        snd_pcm_uframes_t overrange;    /* count of ADC (capture) overrange detections from last status */
        snd_pcm_state_t suspended_state; /* suspended stream state */
-       __u32 reserved_alignment;       /* must be filled with zero */
-       struct timespec audio_tstamp;   /* from sample counter or wall clock */
-       unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */
+       __u32 audio_tstamp_data;         /* needed for 64-bit alignment, used for configs/report to/from userspace */
+       struct timespec audio_tstamp;   /* sample counter, wall clock, PHC or on-demand sync'ed */
+       struct timespec driver_tstamp;  /* useful in case reference system tstamp is reported with delay */
+       __u32 audio_tstamp_accuracy;    /* in ns units, only valid if indicated in audio_tstamp_data */
+       unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
 };
 
 struct snd_pcm_mmap_status {
@@ -534,6 +562,7 @@ enum {
 #define SNDRV_PCM_IOCTL_DELAY          _IOR('A', 0x21, snd_pcm_sframes_t)
 #define SNDRV_PCM_IOCTL_HWSYNC         _IO('A', 0x22)
 #define SNDRV_PCM_IOCTL_SYNC_PTR       _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_STATUS_EXT     _IOWR('A', 0x24, struct snd_pcm_status)
 #define SNDRV_PCM_IOCTL_CHANNEL_INFO   _IOR('A', 0x32, struct snd_pcm_channel_info)
 #define SNDRV_PCM_IOCTL_PREPARE                _IO('A', 0x40)
 #define SNDRV_PCM_IOCTL_RESET          _IO('A', 0x41)
index 22ed8cb7800b40168d236d7f33559298163b398e..e00d8cbfc6282c9f915147d19226aa8eac518b45 100644 (file)
@@ -75,7 +75,7 @@ struct snd_compr_tstamp {
 /**
  * struct snd_compr_avail - avail descriptor
  * @avail: Number of bytes available in ring buffer for writing/reading
- * @tstamp: timestamp infomation
+ * @tstamp: timestamp information
  */
 struct snd_compr_avail {
        __u64 avail;
index d1bbaf78457aed371fe9104641e311d237f53e40..ec1535bb6aedd043df4d5b4950805d8fc2aeaa05 100644 (file)
@@ -23,8 +23,7 @@
 #define _UAPI__SOUND_EMU10K1_H
 
 #include <linux/types.h>
-
-
+#include <sound/asound.h>
 
 /*
  * ---- FX8010 ----
index b357f1a5e29cfa0610fb5ba88b3d2cd5ff355b7b..5737332d38f2cea1f8c2f47f14e9d01282c87a52 100644 (file)
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
 /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
 #define HDSPM_MAX_CHANNELS      64
 
index b9737fae656a89ba6121eddf4804312f2843dc7f..1cbf210080a16c47237f97067c2185eb4f144a23 100644 (file)
@@ -31,7 +31,7 @@ module_param(force, int, 0444);
 MODULE_PARM_DESC(force, "Force loading i2sbus even when"
                        " no layout-id property is present");
 
-static struct of_device_id i2sbus_match[] = {
+static const struct of_device_id i2sbus_match[] = {
        { .name = "i2s" },
        { }
 };
index eeb691d1911f5716bb09b8eecacd24215a31564f..d677c27746e9896fd2181e64390f31cbd7388b2e 100644 (file)
@@ -192,36 +192,41 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
 EXPORT_SYMBOL(snd_ctl_notify);
 
 /**
- * snd_ctl_new - create a control instance from the template
- * @control: the control template
- * @access: the default control access
+ * snd_ctl_new - create a new control instance with some elements
+ * @kctl: the pointer to store new control instance
+ * @count: the number of elements in this control
+ * @access: the default access flags for elements in this control
+ * @file: given when locking these elements
  *
- * Allocates a new struct snd_kcontrol instance and copies the given template 
- * to the new instance. It does not copy volatile data (access).
+ * Allocates a memory object for a new control instance. The instance has
+ * elements as many as the given number (@count). Each element has given
+ * access permissions (@access). Each element is locked when @file is given.
  *
- * Return: The pointer of the new instance, or %NULL on failure.
+ * Return: 0 on success, error code on failure
  */
-static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
-                                       unsigned int access)
+static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
+                      unsigned int access, struct snd_ctl_file *file)
 {
-       struct snd_kcontrol *kctl;
+       unsigned int size;
        unsigned int idx;
        
-       if (snd_BUG_ON(!control || !control->count))
-               return NULL;
+       if (count == 0 || count > MAX_CONTROL_COUNT)
+               return -EINVAL;
 
-       if (control->count > MAX_CONTROL_COUNT)
-               return NULL;
+       size  = sizeof(struct snd_kcontrol);
+       size += sizeof(struct snd_kcontrol_volatile) * count;
 
-       kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
-       if (kctl == NULL) {
-               pr_err("ALSA: Cannot allocate control instance\n");
-               return NULL;
+       *kctl = kzalloc(size, GFP_KERNEL);
+       if (!*kctl)
+               return -ENOMEM;
+
+       for (idx = 0; idx < count; idx++) {
+               (*kctl)->vd[idx].access = access;
+               (*kctl)->vd[idx].owner = file;
        }
-       *kctl = *control;
-       for (idx = 0; idx < kctl->count; idx++)
-               kctl->vd[idx].access = access;
-       return kctl;
+       (*kctl)->count = count;
+
+       return 0;
 }
 
 /**
@@ -238,37 +243,53 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
 struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
                                  void *private_data)
 {
-       struct snd_kcontrol kctl;
+       struct snd_kcontrol *kctl;
+       unsigned int count;
        unsigned int access;
+       int err;
        
        if (snd_BUG_ON(!ncontrol || !ncontrol->info))
                return NULL;
-       memset(&kctl, 0, sizeof(kctl));
-       kctl.id.iface = ncontrol->iface;
-       kctl.id.device = ncontrol->device;
-       kctl.id.subdevice = ncontrol->subdevice;
+
+       count = ncontrol->count;
+       if (count == 0)
+               count = 1;
+
+       access = ncontrol->access;
+       if (access == 0)
+               access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+       access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                  SNDRV_CTL_ELEM_ACCESS_VOLATILE |
+                  SNDRV_CTL_ELEM_ACCESS_INACTIVE |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
+
+       err = snd_ctl_new(&kctl, count, access, NULL);
+       if (err < 0)
+               return NULL;
+
+       /* The 'numid' member is decided when calling snd_ctl_add(). */
+       kctl->id.iface = ncontrol->iface;
+       kctl->id.device = ncontrol->device;
+       kctl->id.subdevice = ncontrol->subdevice;
        if (ncontrol->name) {
-               strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
-               if (strcmp(ncontrol->name, kctl.id.name) != 0)
+               strlcpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name));
+               if (strcmp(ncontrol->name, kctl->id.name) != 0)
                        pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
-                               ncontrol->name, kctl.id.name);
+                               ncontrol->name, kctl->id.name);
        }
-       kctl.id.index = ncontrol->index;
-       kctl.count = ncontrol->count ? ncontrol->count : 1;
-       access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
-                (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
-                                     SNDRV_CTL_ELEM_ACCESS_VOLATILE|
-                                     SNDRV_CTL_ELEM_ACCESS_INACTIVE|
-                                     SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
-                                     SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
-                                     SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
-       kctl.info = ncontrol->info;
-       kctl.get = ncontrol->get;
-       kctl.put = ncontrol->put;
-       kctl.tlv.p = ncontrol->tlv.p;
-       kctl.private_value = ncontrol->private_value;
-       kctl.private_data = private_data;
-       return snd_ctl_new(&kctl, access);
+       kctl->id.index = ncontrol->index;
+
+       kctl->info = ncontrol->info;
+       kctl->get = ncontrol->get;
+       kctl->put = ncontrol->put;
+       kctl->tlv.p = ncontrol->tlv.p;
+
+       kctl->private_value = ncontrol->private_value;
+       kctl->private_data = private_data;
+
+       return kctl;
 }
 EXPORT_SYMBOL(snd_ctl_new1);
 
@@ -1161,84 +1182,102 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
 static int snd_ctl_elem_add(struct snd_ctl_file *file,
                            struct snd_ctl_elem_info *info, int replace)
 {
+       /* The capacity of struct snd_ctl_elem_value.value.*/
+       static const unsigned int value_sizes[] = {
+               [SNDRV_CTL_ELEM_TYPE_BOOLEAN]   = sizeof(long),
+               [SNDRV_CTL_ELEM_TYPE_INTEGER]   = sizeof(long),
+               [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int),
+               [SNDRV_CTL_ELEM_TYPE_BYTES]     = sizeof(unsigned char),
+               [SNDRV_CTL_ELEM_TYPE_IEC958]    = sizeof(struct snd_aes_iec958),
+               [SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long),
+       };
+       static const unsigned int max_value_counts[] = {
+               [SNDRV_CTL_ELEM_TYPE_BOOLEAN]   = 128,
+               [SNDRV_CTL_ELEM_TYPE_INTEGER]   = 128,
+               [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128,
+               [SNDRV_CTL_ELEM_TYPE_BYTES]     = 512,
+               [SNDRV_CTL_ELEM_TYPE_IEC958]    = 1,
+               [SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64,
+       };
        struct snd_card *card = file->card;
-       struct snd_kcontrol kctl, *_kctl;
+       struct snd_kcontrol *kctl;
+       unsigned int count;
        unsigned int access;
        long private_size;
        struct user_element *ue;
-       int idx, err;
+       int err;
 
-       if (info->count < 1)
-               return -EINVAL;
        if (!*info->id.name)
                return -EINVAL;
        if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name))
                return -EINVAL;
-       access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
-               (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
-                                SNDRV_CTL_ELEM_ACCESS_INACTIVE|
-                                SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
-       info->id.numid = 0;
-       memset(&kctl, 0, sizeof(kctl));
 
+       /* Delete a control to replace them if needed. */
        if (replace) {
+               info->id.numid = 0;
                err = snd_ctl_remove_user_ctl(file, &info->id);
                if (err)
                        return err;
        }
 
-       if (card->user_ctl_count >= MAX_USER_CONTROLS)
+       /*
+        * The number of userspace controls are counted control by control,
+        * not element by element.
+        */
+       if (card->user_ctl_count + 1 > MAX_USER_CONTROLS)
                return -ENOMEM;
 
-       memcpy(&kctl.id, &info->id, sizeof(info->id));
-       kctl.count = info->owner ? info->owner : 1;
-       access |= SNDRV_CTL_ELEM_ACCESS_USER;
-       if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
-               kctl.info = snd_ctl_elem_user_enum_info;
-       else
-               kctl.info = snd_ctl_elem_user_info;
-       if (access & SNDRV_CTL_ELEM_ACCESS_READ)
-               kctl.get = snd_ctl_elem_user_get;
-       if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
-               kctl.put = snd_ctl_elem_user_put;
-       if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
-               kctl.tlv.c = snd_ctl_elem_user_tlv;
+       /* Check the number of elements for this userspace control. */
+       count = info->owner;
+       if (count == 0)
+               count = 1;
+
+       /* Arrange access permissions if needed. */
+       access = info->access;
+       if (access == 0)
+               access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+       access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                  SNDRV_CTL_ELEM_ACCESS_INACTIVE |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
+       if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
                access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
-       }
-       switch (info->type) {
-       case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-       case SNDRV_CTL_ELEM_TYPE_INTEGER:
-               private_size = sizeof(long);
-               if (info->count > 128)
-                       return -EINVAL;
-               break;
-       case SNDRV_CTL_ELEM_TYPE_INTEGER64:
-               private_size = sizeof(long long);
-               if (info->count > 64)
-                       return -EINVAL;
-               break;
-       case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-               private_size = sizeof(unsigned int);
-               if (info->count > 128 || info->value.enumerated.items == 0)
-                       return -EINVAL;
-               break;
-       case SNDRV_CTL_ELEM_TYPE_BYTES:
-               private_size = sizeof(unsigned char);
-               if (info->count > 512)
-                       return -EINVAL;
-               break;
-       case SNDRV_CTL_ELEM_TYPE_IEC958:
-               private_size = sizeof(struct snd_aes_iec958);
-               if (info->count != 1)
-                       return -EINVAL;
-               break;
-       default:
+       access |= SNDRV_CTL_ELEM_ACCESS_USER;
+
+       /*
+        * Check information and calculate the size of data specific to
+        * this userspace control.
+        */
+       if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+           info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64)
                return -EINVAL;
-       }
-       private_size *= info->count;
-       ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
-       if (ue == NULL)
+       if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED &&
+           info->value.enumerated.items == 0)
+               return -EINVAL;
+       if (info->count < 1 ||
+           info->count > max_value_counts[info->type])
+               return -EINVAL;
+       private_size = value_sizes[info->type] * info->count;
+
+       /*
+        * Keep memory object for this userspace control. After passing this
+        * code block, the instance should be freed by snd_ctl_free_one().
+        *
+        * Note that these elements in this control are locked.
+        */
+       err = snd_ctl_new(&kctl, count, access, file);
+       if (err < 0)
+               return err;
+       memcpy(&kctl->id, &info->id, sizeof(kctl->id));
+       kctl->private_data = kzalloc(sizeof(struct user_element) + private_size,
+                                    GFP_KERNEL);
+       if (kctl->private_data == NULL) {
+               kfree(kctl);
                return -ENOMEM;
+       }
+       kctl->private_free = snd_ctl_elem_user_free;
+
+       /* Set private data for this userspace control. */
+       ue = (struct user_element *)kctl->private_data;
        ue->card = card;
        ue->info = *info;
        ue->info.access = 0;
@@ -1247,21 +1286,25 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
        if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
                err = snd_ctl_elem_init_enum_names(ue);
                if (err < 0) {
-                       kfree(ue);
+                       snd_ctl_free_one(kctl);
                        return err;
                }
        }
-       kctl.private_free = snd_ctl_elem_user_free;
-       _kctl = snd_ctl_new(&kctl, access);
-       if (_kctl == NULL) {
-               kfree(ue->priv_data);
-               kfree(ue);
-               return -ENOMEM;
-       }
-       _kctl->private_data = ue;
-       for (idx = 0; idx < _kctl->count; idx++)
-               _kctl->vd[idx].owner = file;
-       err = snd_ctl_add(card, _kctl);
+
+       /* Set callback functions. */
+       if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
+               kctl->info = snd_ctl_elem_user_enum_info;
+       else
+               kctl->info = snd_ctl_elem_user_info;
+       if (access & SNDRV_CTL_ELEM_ACCESS_READ)
+               kctl->get = snd_ctl_elem_user_get;
+       if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
+               kctl->put = snd_ctl_elem_user_put;
+       if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
+               kctl->tlv.c = snd_ctl_elem_user_tlv;
+
+       /* This function manage to free the instance on failure. */
+       err = snd_ctl_add(card, kctl);
        if (err < 0)
                return err;
 
index 41bec3075ae5b829c6f032520da7062c6214f662..8918838b1999478e2d03b28dd6425005312bba02 100644 (file)
@@ -50,10 +50,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
        if (snd_BUG_ON(!card || !device_data || !ops))
                return -ENXIO;
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               dev_err(card->dev, "Cannot allocate device, type=%d\n", type);
+       if (!dev)
                return -ENOMEM;
-       }
        INIT_LIST_HEAD(&dev->list);
        dev->card = card;
        dev->type = type;
@@ -73,7 +71,7 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
 }
 EXPORT_SYMBOL(snd_device_new);
 
-static int __snd_device_disconnect(struct snd_device *dev)
+static void __snd_device_disconnect(struct snd_device *dev)
 {
        if (dev->state == SNDRV_DEV_REGISTERED) {
                if (dev->ops->dev_disconnect &&
@@ -81,7 +79,6 @@ static int __snd_device_disconnect(struct snd_device *dev)
                        dev_err(dev->card->dev, "device disconnect failure\n");
                dev->state = SNDRV_DEV_DISCONNECTED;
        }
-       return 0;
 }
 
 static void __snd_device_free(struct snd_device *dev)
@@ -108,6 +105,34 @@ static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
        return NULL;
 }
 
+/**
+ * snd_device_disconnect - disconnect the device
+ * @card: the card instance
+ * @device_data: the data pointer to disconnect
+ *
+ * Turns the device into the disconnection state, invoking
+ * dev_disconnect callback, if the device was already registered.
+ *
+ * Usually called from snd_card_disconnect().
+ *
+ * Return: Zero if successful, or a negative error code on failure or if the
+ * device not found.
+ */
+void snd_device_disconnect(struct snd_card *card, void *device_data)
+{
+       struct snd_device *dev;
+
+       if (snd_BUG_ON(!card || !device_data))
+               return;
+       dev = look_for_dev(card, device_data);
+       if (dev)
+               __snd_device_disconnect(dev);
+       else
+               dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n",
+                       device_data, __builtin_return_address(0));
+}
+EXPORT_SYMBOL_GPL(snd_device_disconnect);
+
 /**
  * snd_device_free - release the device from the card
  * @card: the card instance
@@ -195,18 +220,14 @@ int snd_device_register_all(struct snd_card *card)
  * disconnect all the devices on the card.
  * called from init.c
  */
-int snd_device_disconnect_all(struct snd_card *card)
+void snd_device_disconnect_all(struct snd_card *card)
 {
        struct snd_device *dev;
-       int err = 0;
 
        if (snd_BUG_ON(!card))
-               return -ENXIO;
-       list_for_each_entry_reverse(dev, &card->devices, list) {
-               if (__snd_device_disconnect(dev) < 0)
-                       err = -ENXIO;
-       }
-       return err;
+               return;
+       list_for_each_entry_reverse(dev, &card->devices, list)
+               __snd_device_disconnect(dev);
 }
 
 /*
index 84244a5143cfe91fb53c5cfc1e2f9f5818d588aa..51692c8a39ea1b5fe99ab197e47c29dc16aaf86f 100644 (file)
@@ -378,10 +378,8 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
        if (rhwdep)
                *rhwdep = NULL;
        hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
-       if (hwdep == NULL) {
-               dev_err(card->dev, "hwdep: cannot allocate\n");
+       if (!hwdep)
                return -ENOMEM;
-       }
 
        init_waitqueue_head(&hwdep->open_wait);
        mutex_init(&hwdep->open_mutex);
index 35419054821c3deab7e590b6a586f05d1282d055..04734e047bfe47e9bba67ace601b75db438608ed 100644 (file)
@@ -400,7 +400,6 @@ static const struct file_operations snd_shutdown_f_ops =
 int snd_card_disconnect(struct snd_card *card)
 {
        struct snd_monitor_file *mfile;
-       int err;
 
        if (!card)
                return -EINVAL;
@@ -445,9 +444,7 @@ int snd_card_disconnect(struct snd_card *card)
 #endif
 
        /* notify all devices that we are disconnected */
-       err = snd_device_disconnect_all(card);
-       if (err < 0)
-               dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
+       snd_device_disconnect_all(card);
 
        snd_info_card_disconnect(card);
        if (card->registered) {
index 5e6349f00ecd770a3c572ef950454ec04f13e1c8..056f8e27485181208a85fd2142cd7f13297a3a6d 100644 (file)
@@ -1212,10 +1212,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                        /* not changed */
                        goto __unlock;
                tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
-               if (! tbl) {
-                       pr_err("ALSA: mixer_oss: no memory\n");
+               if (!tbl)
                        goto __unlock;
-               }
                tbl->oss_id = ch;
                tbl->name = kstrdup(str, GFP_KERNEL);
                if (! tbl->name) {
index 80423a4ccab621b04d0c0fbdbe3bdeafc67a7e3b..58550cc93f2805aa8627f9e3e4588c2838281926 100644 (file)
@@ -854,7 +854,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        params = kmalloc(sizeof(*params), GFP_KERNEL);
        sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
        if (!sw_params || !params || !sparams) {
-               pcm_dbg(substream->pcm, "No memory\n");
                err = -ENOMEM;
                goto failure;
        }
index 0345e53a340ca90d68fa3f4b05b3a7e655ebdb1f..b25bcf5b8644636f05eacb3f38bcae2ad462f6f6 100644 (file)
@@ -49,8 +49,6 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
        struct snd_pcm *pcm;
 
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
-               if (pcm->internal)
-                       continue;
                if (pcm->card == card && pcm->device == device)
                        return pcm;
        }
@@ -62,8 +60,6 @@ static int snd_pcm_next(struct snd_card *card, int device)
        struct snd_pcm *pcm;
 
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
-               if (pcm->internal)
-                       continue;
                if (pcm->card == card && pcm->device > device)
                        return pcm->device;
                else if (pcm->card->number > card->number)
@@ -76,6 +72,9 @@ static int snd_pcm_add(struct snd_pcm *newpcm)
 {
        struct snd_pcm *pcm;
 
+       if (newpcm->internal)
+               return 0;
+
        list_for_each_entry(pcm, &snd_pcm_devices, list) {
                if (pcm->card == newpcm->card && pcm->device == newpcm->device)
                        return -EBUSY;
@@ -344,11 +343,8 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
                return;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (! info) {
-               pcm_dbg(substream->pcm,
-                       "snd_pcm_proc_info_read: cannot malloc\n");
+       if (!info)
                return;
-       }
 
        err = snd_pcm_info(substream, info);
        if (err < 0) {
@@ -718,10 +714,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
        prev = NULL;
        for (idx = 0, prev = NULL; idx < substream_count; idx++) {
                substream = kzalloc(sizeof(*substream), GFP_KERNEL);
-               if (substream == NULL) {
-                       pcm_err(pcm, "Cannot allocate PCM substream\n");
+               if (!substream)
                        return -ENOMEM;
-               }
                substream->pcm = pcm;
                substream->pstr = pstr;
                substream->number = idx;
@@ -775,13 +769,14 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
        if (rpcm)
                *rpcm = NULL;
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
-       if (pcm == NULL) {
-               dev_err(card->dev, "Cannot allocate PCM\n");
+       if (!pcm)
                return -ENOMEM;
-       }
        pcm->card = card;
        pcm->device = device;
        pcm->internal = internal;
+       mutex_init(&pcm->open_mutex);
+       init_waitqueue_head(&pcm->open_wait);
+       INIT_LIST_HEAD(&pcm->list);
        if (id)
                strlcpy(pcm->id, id, sizeof(pcm->id));
        if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
@@ -792,8 +787,6 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
                snd_pcm_free(pcm);
                return err;
        }
-       mutex_init(&pcm->open_mutex);
-       init_waitqueue_head(&pcm->open_wait);
        if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
                snd_pcm_free(pcm);
                return err;
@@ -888,8 +881,9 @@ static int snd_pcm_free(struct snd_pcm *pcm)
 
        if (!pcm)
                return 0;
-       list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-               notify->n_unregister(pcm);
+       if (!pcm->internal) {
+               list_for_each_entry(notify, &snd_pcm_notify_list, list)
+                       notify->n_unregister(pcm);
        }
        if (pcm->private_free)
                pcm->private_free(pcm);
@@ -919,6 +913,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 
        if (snd_BUG_ON(!pcm || !rsubstream))
                return -ENXIO;
+       if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK &&
+                      stream != SNDRV_PCM_STREAM_CAPTURE))
+               return -EINVAL;
        *rsubstream = NULL;
        pstr = &pcm->streams[stream];
        if (pstr->substream == NULL || pstr->substream_count == 0)
@@ -927,25 +924,14 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        card = pcm->card;
        prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
 
-       switch (stream) {
-       case SNDRV_PCM_STREAM_PLAYBACK:
-               if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-                       for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {
-                               if (SUBSTREAM_BUSY(substream))
-                                       return -EAGAIN;
-                       }
-               }
-               break;
-       case SNDRV_PCM_STREAM_CAPTURE:
-               if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-                       for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {
-                               if (SUBSTREAM_BUSY(substream))
-                                       return -EAGAIN;
-                       }
+       if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
+               int opposite = !stream;
+
+               for (substream = pcm->streams[opposite].substream; substream;
+                    substream = substream->next) {
+                       if (SUBSTREAM_BUSY(substream))
+                               return -EAGAIN;
                }
-               break;
-       default:
-               return -EINVAL;
        }
 
        if (file->f_flags & O_APPEND) {
@@ -968,15 +954,12 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                return 0;
        }
 
-       if (prefer_subdevice >= 0) {
-               for (substream = pstr->substream; substream; substream = substream->next)
-                       if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
-                               goto __ok;
-       }
-       for (substream = pstr->substream; substream; substream = substream->next)
-               if (!SUBSTREAM_BUSY(substream))
+       for (substream = pstr->substream; substream; substream = substream->next) {
+               if (!SUBSTREAM_BUSY(substream) &&
+                   (prefer_subdevice == -1 ||
+                    substream->number == prefer_subdevice))
                        break;
-      __ok:
+       }
        if (substream == NULL)
                return -EAGAIN;
 
@@ -1086,15 +1069,16 @@ static int snd_pcm_dev_register(struct snd_device *device)
        if (snd_BUG_ON(!device || !device->device_data))
                return -ENXIO;
        pcm = device->device_data;
+       if (pcm->internal)
+               return 0;
+
        mutex_lock(&register_mutex);
        err = snd_pcm_add(pcm);
-       if (err) {
-               mutex_unlock(&register_mutex);
-               return err;
-       }
+       if (err)
+               goto unlock;
        for (cidx = 0; cidx < 2; cidx++) {
                int devtype = -1;
-               if (pcm->streams[cidx].substream == NULL || pcm->internal)
+               if (pcm->streams[cidx].substream == NULL)
                        continue;
                switch (cidx) {
                case SNDRV_PCM_STREAM_PLAYBACK:
@@ -1109,9 +1093,8 @@ static int snd_pcm_dev_register(struct snd_device *device)
                                          &snd_pcm_f_ops[cidx], pcm,
                                          &pcm->streams[cidx].dev);
                if (err < 0) {
-                       list_del(&pcm->list);
-                       mutex_unlock(&register_mutex);
-                       return err;
+                       list_del_init(&pcm->list);
+                       goto unlock;
                }
 
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -1121,8 +1104,9 @@ static int snd_pcm_dev_register(struct snd_device *device)
        list_for_each_entry(notify, &snd_pcm_notify_list, list)
                notify->n_register(pcm);
 
+ unlock:
        mutex_unlock(&register_mutex);
-       return 0;
+       return err;
 }
 
 static int snd_pcm_dev_disconnect(struct snd_device *device)
@@ -1133,13 +1117,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
        int cidx;
 
        mutex_lock(&register_mutex);
-       if (list_empty(&pcm->list))
-               goto unlock;
-
        mutex_lock(&pcm->open_mutex);
        wake_up(&pcm->open_wait);
        list_del_init(&pcm->list);
-       for (cidx = 0; cidx < 2; cidx++)
+       for (cidx = 0; cidx < 2; cidx++) {
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
                        snd_pcm_stream_lock_irq(substream);
                        if (substream->runtime) {
@@ -1149,18 +1130,20 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
                        }
                        snd_pcm_stream_unlock_irq(substream);
                }
-       list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-               notify->n_disconnect(pcm);
+       }
+       if (!pcm->internal) {
+               list_for_each_entry(notify, &snd_pcm_notify_list, list)
+                       notify->n_disconnect(pcm);
        }
        for (cidx = 0; cidx < 2; cidx++) {
-               snd_unregister_device(&pcm->streams[cidx].dev);
+               if (!pcm->internal)
+                       snd_unregister_device(&pcm->streams[cidx].dev);
                if (pcm->streams[cidx].chmap_kctl) {
                        snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
                        pcm->streams[cidx].chmap_kctl = NULL;
                }
        }
        mutex_unlock(&pcm->open_mutex);
- unlock:
        mutex_unlock(&register_mutex);
        return 0;
 }
index 2d957ba635578758172c9d66addc181a3ce438a9..b48b434444ed0e0239936887a891d15da0054e00 100644 (file)
@@ -194,18 +194,30 @@ struct snd_pcm_status32 {
        u32 avail_max;
        u32 overrange;
        s32 suspended_state;
-       u32 reserved_alignment;
+       u32 audio_tstamp_data;
        struct compat_timespec audio_tstamp;
-       unsigned char reserved[56-sizeof(struct compat_timespec)];
+       struct compat_timespec driver_tstamp;
+       u32 audio_tstamp_accuracy;
+       unsigned char reserved[52-2*sizeof(struct compat_timespec)];
 } __attribute__((packed));
 
 
 static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
-                                     struct snd_pcm_status32 __user *src)
+                                     struct snd_pcm_status32 __user *src,
+                                     bool ext)
 {
        struct snd_pcm_status status;
        int err;
 
+       memset(&status, 0, sizeof(status));
+       /*
+        * with extension, parameters are read/write,
+        * get audio_tstamp_data from user,
+        * ignore rest of status structure
+        */
+       if (ext && get_user(status.audio_tstamp_data,
+                               (u32 __user *)(&src->audio_tstamp_data)))
+               return -EFAULT;
        err = snd_pcm_status(substream, &status);
        if (err < 0)
                return err;
@@ -222,7 +234,10 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
            put_user(status.avail_max, &src->avail_max) ||
            put_user(status.overrange, &src->overrange) ||
            put_user(status.suspended_state, &src->suspended_state) ||
-           compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp))
+           put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
+           compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
+           compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
+           put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
                return -EFAULT;
 
        return err;
@@ -457,6 +472,7 @@ enum {
        SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
        SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
        SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32),
+       SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
        SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
        SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
        SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
@@ -517,7 +533,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
        case SNDRV_PCM_IOCTL_SW_PARAMS32:
                return snd_pcm_ioctl_sw_params_compat(substream, argp);
        case SNDRV_PCM_IOCTL_STATUS32:
-               return snd_pcm_status_user_compat(substream, argp);
+               return snd_pcm_status_user_compat(substream, argp, false);
+       case SNDRV_PCM_IOCTL_STATUS_EXT32:
+               return snd_pcm_status_user_compat(substream, argp, true);
        case SNDRV_PCM_IOCTL_SYNC_PTR32:
                return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
        case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
index 6542c40835949f4df5d071d1c20384fa73329577..fba365a783909f50c61d2d247cc0de06c775ff49 100644 (file)
@@ -289,7 +289,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
  *
  * The function should usually be called from the pcm open callback. Note that
  * this function will use private_data field of the substream's runtime. So it
- * is not availabe to your pcm driver implementation.
+ * is not available to your pcm driver implementation.
  */
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
        struct dma_chan *chan)
@@ -328,7 +328,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
  * This function will request a DMA channel using the passed filter function and
  * data. The function should usually be called from the pcm open callback. Note
  * that this function will use private_data field of the substream's runtime. So
- * it is not availabe to your pcm driver implementation.
+ * it is not available to your pcm driver implementation.
  */
 int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
        dma_filter_fn filter_fn, void *filter_data)
index ffd656012ab8cf123faef551c9eaaae48c2beb8c..ac6b33f3779c2ee8a08fe80aa64172d3858d452b 100644 (file)
@@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static void update_audio_tstamp(struct snd_pcm_substream *substream,
+                               struct timespec *curr_tstamp,
+                               struct timespec *audio_tstamp)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       u64 audio_frames, audio_nsecs;
+       struct timespec driver_tstamp;
+
+       if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
+               return;
+
+       if (!(substream->ops->get_time_info) ||
+               (runtime->audio_tstamp_report.actual_type ==
+                       SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
+
+               /*
+                * provide audio timestamp derived from pointer position
+                * add delay only if requested
+                */
+
+               audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr;
+
+               if (runtime->audio_tstamp_config.report_delay) {
+                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                               audio_frames -=  runtime->delay;
+                       else
+                               audio_frames +=  runtime->delay;
+               }
+               audio_nsecs = div_u64(audio_frames * 1000000000LL,
+                               runtime->rate);
+               *audio_tstamp = ns_to_timespec(audio_nsecs);
+       }
+       runtime->status->audio_tstamp = *audio_tstamp;
+       runtime->status->tstamp = *curr_tstamp;
+
+       /*
+        * re-take a driver timestamp to let apps detect if the reference tstamp
+        * read by low-level hardware was provided with a delay
+        */
+       snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp);
+       runtime->driver_tstamp = driver_tstamp;
+}
+
 static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                                  unsigned int in_interrupt)
 {
@@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        pos = substream->ops->pointer(substream);
        curr_jiffies = jiffies;
        if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
-               snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
-
-               if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
-                       (substream->ops->wall_clock))
-                       substream->ops->wall_clock(substream, &audio_tstamp);
+               if ((substream->ops->get_time_info) &&
+                       (runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
+                       substream->ops->get_time_info(substream, &curr_tstamp,
+                                               &audio_tstamp,
+                                               &runtime->audio_tstamp_config,
+                                               &runtime->audio_tstamp_report);
+
+                       /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
+                       if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
+                               snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
+               } else
+                       snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
        }
 
        if (pos == SNDRV_PCM_POS_XRUN) {
@@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        }
 
  no_delta_check:
-       if (runtime->status->hw_ptr == new_hw_ptr)
+       if (runtime->status->hw_ptr == new_hw_ptr) {
+               update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
                return 0;
+       }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
@@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                snd_BUG_ON(crossed_boundary != 1);
                runtime->hw_ptr_wrap += runtime->boundary;
        }
-       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
-               runtime->status->tstamp = curr_tstamp;
 
-               if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) {
-                       /*
-                        * no wall clock available, provide audio timestamp
-                        * derived from pointer position+delay
-                        */
-                       u64 audio_frames, audio_nsecs;
-
-                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                               audio_frames = runtime->hw_ptr_wrap
-                                       + runtime->status->hw_ptr
-                                       - runtime->delay;
-                       else
-                               audio_frames = runtime->hw_ptr_wrap
-                                       + runtime->status->hw_ptr
-                                       + runtime->delay;
-                       audio_nsecs = div_u64(audio_frames * 1000000000LL,
-                                       runtime->rate);
-                       audio_tstamp = ns_to_timespec(audio_nsecs);
-               }
-               runtime->status->audio_tstamp = audio_tstamp;
-       }
+       update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
 
        return snd_pcm_update_state(substream, runtime);
 }
index 279e24f613051fddb8ca16375ab9031e6a703b03..abe1e811e660df3f71695d1077313493acbdd2ee 100644 (file)
@@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        snd_pcm_stream_lock_irq(substream);
+
+       snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
+                                       &runtime->audio_tstamp_config);
+
+       /* backwards compatible behavior */
+       if (runtime->audio_tstamp_config.type_requested ==
+               SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) {
+               if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)
+                       runtime->audio_tstamp_config.type_requested =
+                               SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
+               else
+                       runtime->audio_tstamp_config.type_requested =
+                               SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
+               runtime->audio_tstamp_report.valid = 0;
+       } else
+               runtime->audio_tstamp_report.valid = 1;
+
        status->state = runtime->status->state;
        status->suspended_state = runtime->status->suspended_state;
        if (status->state == SNDRV_PCM_STATE_OPEN)
@@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
                snd_pcm_update_hw_ptr(substream);
                if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
                        status->tstamp = runtime->status->tstamp;
+                       status->driver_tstamp = runtime->driver_tstamp;
                        status->audio_tstamp =
                                runtime->status->audio_tstamp;
+                       if (runtime->audio_tstamp_report.valid == 1)
+                               /* backwards compatibility, no report provided in COMPAT mode */
+                               snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
+                                                               &status->audio_tstamp_accuracy,
+                                                               &runtime->audio_tstamp_report);
+
                        goto _tstamp_end;
                }
        } else {
@@ -753,12 +777,21 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 }
 
 static int snd_pcm_status_user(struct snd_pcm_substream *substream,
-                              struct snd_pcm_status __user * _status)
+                              struct snd_pcm_status __user * _status,
+                              bool ext)
 {
        struct snd_pcm_status status;
        int res;
-       
+
        memset(&status, 0, sizeof(status));
+       /*
+        * with extension, parameters are read/write,
+        * get audio_tstamp_data from user,
+        * ignore rest of status structure
+        */
+       if (ext && get_user(status.audio_tstamp_data,
+                               (u32 __user *)(&_status->audio_tstamp_data)))
+               return -EFAULT;
        res = snd_pcm_status(substream, &status);
        if (res < 0)
                return res;
@@ -2725,7 +2758,9 @@ static int snd_pcm_common_ioctl1(struct file *file,
        case SNDRV_PCM_IOCTL_SW_PARAMS:
                return snd_pcm_sw_params_user(substream, arg);
        case SNDRV_PCM_IOCTL_STATUS:
-               return snd_pcm_status_user(substream, arg);
+               return snd_pcm_status_user(substream, arg, false);
+       case SNDRV_PCM_IOCTL_STATUS_EXT:
+               return snd_pcm_status_user(substream, arg, true);
        case SNDRV_PCM_IOCTL_CHANNEL_INFO:
                return snd_pcm_channel_info_user(substream, arg);
        case SNDRV_PCM_IOCTL_PREPARE:
index b5a748596fc40dda977e437b2ed6a6b87c4321b3..a7759846fbaadff0c9493760ce7b14eff7ca8ad9 100644 (file)
@@ -1429,10 +1429,8 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
 
        for (idx = 0; idx < count; idx++) {
                substream = kzalloc(sizeof(*substream), GFP_KERNEL);
-               if (substream == NULL) {
-                       rmidi_err(rmidi, "rawmidi: cannot allocate substream\n");
+               if (!substream)
                        return -ENOMEM;
-               }
                substream->stream = direction;
                substream->number = idx;
                substream->rmidi = rmidi;
@@ -1479,10 +1477,8 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
        if (rrawmidi)
                *rrawmidi = NULL;
        rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
-       if (rmidi == NULL) {
-               dev_err(card->dev, "rawmidi: cannot allocate\n");
+       if (!rmidi)
                return -ENOMEM;
-       }
        rmidi->card = card;
        rmidi->device = device;
        mutex_init(&rmidi->open_mutex);
index 16d42679e43fc29e380612274e9f597f9899dc91..72873a46afeb391f51a27da171c853d131e395f7 100644 (file)
@@ -65,15 +65,20 @@ static unsigned int odev_poll(struct file *file, poll_table * wait);
  * module interface
  */
 
+static struct snd_seq_driver seq_oss_synth_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .probe = snd_seq_oss_synth_probe,
+               .remove = snd_seq_oss_synth_remove,
+       },
+       .id = SNDRV_SEQ_DEV_ID_OSS,
+       .argsize = sizeof(struct snd_seq_oss_reg),
+};
+
 static int __init alsa_seq_oss_init(void)
 {
        int rc;
-       static struct snd_seq_dev_ops ops = {
-               snd_seq_oss_synth_register,
-               snd_seq_oss_synth_unregister,
-       };
 
-       snd_seq_autoload_lock();
        if ((rc = register_device()) < 0)
                goto error;
        if ((rc = register_proc()) < 0) {
@@ -86,8 +91,8 @@ static int __init alsa_seq_oss_init(void)
                goto error;
        }
 
-       if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops,
-                                                sizeof(struct snd_seq_oss_reg))) < 0) {
+       rc = snd_seq_driver_register(&seq_oss_synth_driver);
+       if (rc < 0) {
                snd_seq_oss_delete_client();
                unregister_proc();
                unregister_device();
@@ -98,13 +103,12 @@ static int __init alsa_seq_oss_init(void)
        snd_seq_oss_synth_init();
 
  error:
-       snd_seq_autoload_unlock();
        return rc;
 }
 
 static void __exit alsa_seq_oss_exit(void)
 {
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS);
+       snd_seq_driver_unregister(&seq_oss_synth_driver);
        snd_seq_oss_delete_client();
        unregister_proc();
        unregister_device();
index b0e32e161dd187564e7d869d12651f2241eddd07..2de3feff70d06d275a824101829a4b3f1064e781 100644 (file)
@@ -188,10 +188,8 @@ snd_seq_oss_open(struct file *file, int level)
        struct seq_oss_devinfo *dp;
 
        dp = kzalloc(sizeof(*dp), GFP_KERNEL);
-       if (!dp) {
-               pr_err("ALSA: seq_oss: can't malloc device info\n");
+       if (!dp)
                return -ENOMEM;
-       }
 
        dp->cseq = system_client;
        dp->port = -1;
index e79cc44b1394e68c07d8eab6c00c3868522f8c03..96e8395ae5863e85a9e4a59c2ca870f9481de141 100644 (file)
@@ -173,10 +173,9 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
        /*
         * allocate midi info record
         */
-       if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) {
-               pr_err("ALSA: seq_oss: can't malloc midi info\n");
+       mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+       if (!mdev)
                return -ENOMEM;
-       }
 
        /* copy the port information */
        mdev->client = pinfo->addr.client;
index 654d17a5023c8a23e2ec5f799298d91dc0c7f457..c080c73cea04a258599fe58cd60473cfab77e1fc 100644 (file)
@@ -47,13 +47,12 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
 {
        struct seq_oss_readq *q;
 
-       if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) {
-               pr_err("ALSA: seq_oss: can't malloc read queue\n");
+       q = kzalloc(sizeof(*q), GFP_KERNEL);
+       if (!q)
                return NULL;
-       }
 
-       if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) {
-               pr_err("ALSA: seq_oss: can't malloc read queue buffer\n");
+       q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL);
+       if (!q->q) {
                kfree(q);
                return NULL;
        }
index 701feb71b700c7e223633b07827e954a804e5825..48e4fe1b68abba6e2dcb25c365a82d04c647e8c7 100644 (file)
@@ -98,17 +98,17 @@ snd_seq_oss_synth_init(void)
  * registration of the synth device
  */
 int
-snd_seq_oss_synth_register(struct snd_seq_device *dev)
+snd_seq_oss_synth_probe(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        int i;
        struct seq_oss_synth *rec;
        struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
        unsigned long flags;
 
-       if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) {
-               pr_err("ALSA: seq_oss: can't malloc synth info\n");
+       rec = kzalloc(sizeof(*rec), GFP_KERNEL);
+       if (!rec)
                return -ENOMEM;
-       }
        rec->seq_device = -1;
        rec->synth_type = reg->type;
        rec->synth_subtype = reg->subtype;
@@ -149,8 +149,9 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
 
 
 int
-snd_seq_oss_synth_unregister(struct snd_seq_device *dev)
+snd_seq_oss_synth_remove(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        int index;
        struct seq_oss_synth *rec = dev->driver_data;
        unsigned long flags;
@@ -247,7 +248,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
                if (info->nr_voices > 0) {
                        info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
                        if (!info->ch) {
-                               pr_err("ALSA: seq_oss: Cannot malloc voices\n");
                                rec->oper.close(&info->arg);
                                module_put(rec->oper.owner);
                                snd_use_lock_free(&rec->use_lock);
index dbdfcbb80eaa2bdb224562770cda13ec866021a9..74ac55f166b6517751d197c14a5aaf4b6805ca01 100644 (file)
@@ -28,8 +28,8 @@
 #include <sound/seq_device.h>
 
 void snd_seq_oss_synth_init(void);
-int snd_seq_oss_synth_register(struct snd_seq_device *dev);
-int snd_seq_oss_synth_unregister(struct snd_seq_device *dev);
+int snd_seq_oss_synth_probe(struct device *dev);
+int snd_seq_oss_synth_remove(struct device *dev);
 void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp);
 void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp);
 void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp);
index 0631bdadd12bd6ca884bf68578ac8fd7917a3f6b..d99f99d61983a204e0c60f3a455b6fa856b48f6a 100644 (file)
@@ -36,6 +36,7 @@
  *
  */
 
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <sound/core.h>
@@ -51,140 +52,78 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA sequencer device management");
 MODULE_LICENSE("GPL");
 
-/* driver state */
-#define DRIVER_EMPTY           0
-#define DRIVER_LOADED          (1<<0)
-#define DRIVER_REQUESTED       (1<<1)
-#define DRIVER_LOCKED          (1<<2)
-#define DRIVER_REQUESTING      (1<<3)
-
-struct ops_list {
-       char id[ID_LEN];        /* driver id */
-       int driver;             /* driver state */
-       int used;               /* reference counter */
-       int argsize;            /* argument size */
-
-       /* operators */
-       struct snd_seq_dev_ops ops;
-
-       /* registered devices */
-       struct list_head dev_list;      /* list of devices */
-       int num_devices;        /* number of associated devices */
-       int num_init_devices;   /* number of initialized devices */
-       struct mutex reg_mutex;
-
-       struct list_head list;  /* next driver */
-};
+/*
+ * bus definition
+ */
+static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct snd_seq_device *sdev = to_seq_dev(dev);
+       struct snd_seq_driver *sdrv = to_seq_drv(drv);
 
+       return strcmp(sdrv->id, sdev->id) == 0 &&
+               sdrv->argsize == sdev->argsize;
+}
 
-static LIST_HEAD(opslist);
-static int num_ops;
-static DEFINE_MUTEX(ops_mutex);
-#ifdef CONFIG_PROC_FS
-static struct snd_info_entry *info_entry;
-#endif
+static struct bus_type snd_seq_bus_type = {
+       .name = "snd_seq",
+       .match = snd_seq_bus_match,
+};
 
 /*
- * prototypes
+ * proc interface -- just for compatibility
  */
-static int snd_seq_device_free(struct snd_seq_device *dev);
-static int snd_seq_device_dev_free(struct snd_device *device);
-static int snd_seq_device_dev_register(struct snd_device *device);
-static int snd_seq_device_dev_disconnect(struct snd_device *device);
-
-static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
-static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
-static struct ops_list *find_driver(char *id, int create_if_empty);
-static struct ops_list *create_driver(char *id);
-static void unlock_driver(struct ops_list *ops);
-static void remove_drivers(void);
+#ifdef CONFIG_PROC_FS
+static struct snd_info_entry *info_entry;
 
-/*
- * show all drivers and their status
- */
+static int print_dev_info(struct device *dev, void *data)
+{
+       struct snd_seq_device *sdev = to_seq_dev(dev);
+       struct snd_info_buffer *buffer = data;
+
+       snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id,
+                   dev->driver ? "loaded" : "empty",
+                   dev->driver ? 1 : 0);
+       return 0;
+}
 
-#ifdef CONFIG_PROC_FS
 static void snd_seq_device_info(struct snd_info_entry *entry,
                                struct snd_info_buffer *buffer)
 {
-       struct ops_list *ops;
-
-       mutex_lock(&ops_mutex);
-       list_for_each_entry(ops, &opslist, list) {
-               snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
-                               ops->id,
-                               ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
-                               ops->driver & DRIVER_REQUESTED ? ",requested" : "",
-                               ops->driver & DRIVER_LOCKED ? ",locked" : "",
-                               ops->num_devices);
-       }
-       mutex_unlock(&ops_mutex);
+       bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info);
 }
 #endif
+
 /*
  * load all registered drivers (called from seq_clientmgr.c)
  */
 
 #ifdef CONFIG_MODULES
-/* avoid auto-loading during module_init() */
+/* flag to block auto-loading */
 static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
-void snd_seq_autoload_lock(void)
-{
-       atomic_inc(&snd_seq_in_init);
-}
 
-void snd_seq_autoload_unlock(void)
+static int request_seq_drv(struct device *dev, void *data)
 {
-       atomic_dec(&snd_seq_in_init);
+       struct snd_seq_device *sdev = to_seq_dev(dev);
+
+       if (!dev->driver)
+               request_module("snd-%s", sdev->id);
+       return 0;
 }
 
-static void autoload_drivers(void)
+static void autoload_drivers(struct work_struct *work)
 {
        /* avoid reentrance */
-       if (atomic_inc_return(&snd_seq_in_init) == 1) {
-               struct ops_list *ops;
-
-               mutex_lock(&ops_mutex);
-               list_for_each_entry(ops, &opslist, list) {
-                       if ((ops->driver & DRIVER_REQUESTING) &&
-                           !(ops->driver & DRIVER_REQUESTED)) {
-                               ops->used++;
-                               mutex_unlock(&ops_mutex);
-                               ops->driver |= DRIVER_REQUESTED;
-                               request_module("snd-%s", ops->id);
-                               mutex_lock(&ops_mutex);
-                               ops->used--;
-                       }
-               }
-               mutex_unlock(&ops_mutex);
-       }
+       if (atomic_inc_return(&snd_seq_in_init) == 1)
+               bus_for_each_dev(&snd_seq_bus_type, NULL, NULL,
+                                request_seq_drv);
        atomic_dec(&snd_seq_in_init);
 }
 
-static void call_autoload(struct work_struct *work)
-{
-       autoload_drivers();
-}
-
-static DECLARE_WORK(autoload_work, call_autoload);
-
-static void try_autoload(struct ops_list *ops)
-{
-       if (!ops->driver) {
-               ops->driver |= DRIVER_REQUESTING;
-               schedule_work(&autoload_work);
-       }
-}
+static DECLARE_WORK(autoload_work, autoload_drivers);
 
 static void queue_autoload_drivers(void)
 {
-       struct ops_list *ops;
-
-       mutex_lock(&ops_mutex);
-       list_for_each_entry(ops, &opslist, list)
-               try_autoload(ops);
-       mutex_unlock(&ops_mutex);
+       schedule_work(&autoload_work);
 }
 
 void snd_seq_autoload_init(void)
@@ -195,384 +134,143 @@ void snd_seq_autoload_init(void)
        queue_autoload_drivers();
 #endif
 }
-#else
-#define try_autoload(ops) /* NOP */
-#endif
+EXPORT_SYMBOL(snd_seq_autoload_init);
 
-void snd_seq_device_load_drivers(void)
+void snd_seq_autoload_exit(void)
 {
-#ifdef CONFIG_MODULES
-       queue_autoload_drivers();
-       flush_work(&autoload_work);
-#endif
+       atomic_inc(&snd_seq_in_init);
 }
+EXPORT_SYMBOL(snd_seq_autoload_exit);
 
-/*
- * register a sequencer device
- * card = card info
- * device = device number (if any)
- * id = id of driver
- * result = return pointer (NULL allowed if unnecessary)
- */
-int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
-                      struct snd_seq_device **result)
+void snd_seq_device_load_drivers(void)
 {
-       struct snd_seq_device *dev;
-       struct ops_list *ops;
-       int err;
-       static struct snd_device_ops dops = {
-               .dev_free = snd_seq_device_dev_free,
-               .dev_register = snd_seq_device_dev_register,
-               .dev_disconnect = snd_seq_device_dev_disconnect,
-       };
-
-       if (result)
-               *result = NULL;
-
-       if (snd_BUG_ON(!id))
-               return -EINVAL;
-
-       ops = find_driver(id, 1);
-       if (ops == NULL)
-               return -ENOMEM;
-
-       dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL);
-       if (dev == NULL) {
-               unlock_driver(ops);
-               return -ENOMEM;
-       }
-
-       /* set up device info */
-       dev->card = card;
-       dev->device = device;
-       strlcpy(dev->id, id, sizeof(dev->id));
-       dev->argsize = argsize;
-       dev->status = SNDRV_SEQ_DEVICE_FREE;
-
-       /* add this device to the list */
-       mutex_lock(&ops->reg_mutex);
-       list_add_tail(&dev->list, &ops->dev_list);
-       ops->num_devices++;
-       mutex_unlock(&ops->reg_mutex);
-
-       if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
-               snd_seq_device_free(dev);
-               return err;
-       }
-       
-       try_autoload(ops);
-       unlock_driver(ops);
-
-       if (result)
-               *result = dev;
-
-       return 0;
+       queue_autoload_drivers();
+       flush_work(&autoload_work);
 }
+EXPORT_SYMBOL(snd_seq_device_load_drivers);
+#else
+#define queue_autoload_drivers() /* NOP */
+#endif
 
 /*
- * free the existing device
+ * device management
  */
-static int snd_seq_device_free(struct snd_seq_device *dev)
-{
-       struct ops_list *ops;
-
-       if (snd_BUG_ON(!dev))
-               return -EINVAL;
-
-       ops = find_driver(dev->id, 0);
-       if (ops == NULL)
-               return -ENXIO;
-
-       /* remove the device from the list */
-       mutex_lock(&ops->reg_mutex);
-       list_del(&dev->list);
-       ops->num_devices--;
-       mutex_unlock(&ops->reg_mutex);
-
-       free_device(dev, ops);
-       if (dev->private_free)
-               dev->private_free(dev);
-       kfree(dev);
-
-       unlock_driver(ops);
-
-       return 0;
-}
-
 static int snd_seq_device_dev_free(struct snd_device *device)
 {
        struct snd_seq_device *dev = device->device_data;
-       return snd_seq_device_free(dev);
+
+       put_device(&dev->dev);
+       return 0;
 }
 
-/*
- * register the device
- */
 static int snd_seq_device_dev_register(struct snd_device *device)
 {
        struct snd_seq_device *dev = device->device_data;
-       struct ops_list *ops;
-
-       ops = find_driver(dev->id, 0);
-       if (ops == NULL)
-               return -ENOENT;
-
-       /* initialize this device if the corresponding driver was
-        * already loaded
-        */
-       if (ops->driver & DRIVER_LOADED)
-               init_device(dev, ops);
+       int err;
 
-       unlock_driver(ops);
+       err = device_add(&dev->dev);
+       if (err < 0)
+               return err;
+       if (!dev->dev.driver)
+               queue_autoload_drivers();
        return 0;
 }
 
-/*
- * disconnect the device
- */
 static int snd_seq_device_dev_disconnect(struct snd_device *device)
 {
        struct snd_seq_device *dev = device->device_data;
-       struct ops_list *ops;
-
-       ops = find_driver(dev->id, 0);
-       if (ops == NULL)
-               return -ENOENT;
-
-       free_device(dev, ops);
 
-       unlock_driver(ops);
+       device_del(&dev->dev);
        return 0;
 }
 
-/*
- * register device driver
- * id = driver id
- * entry = driver operators - duplicated to each instance
- */
-int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
-                                  int argsize)
+static void snd_seq_dev_release(struct device *dev)
 {
-       struct ops_list *ops;
-       struct snd_seq_device *dev;
+       struct snd_seq_device *sdev = to_seq_dev(dev);
 
-       if (id == NULL || entry == NULL ||
-           entry->init_device == NULL || entry->free_device == NULL)
-               return -EINVAL;
-
-       ops = find_driver(id, 1);
-       if (ops == NULL)
-               return -ENOMEM;
-       if (ops->driver & DRIVER_LOADED) {
-               pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
-               unlock_driver(ops);
-               return -EBUSY;
-       }
-
-       mutex_lock(&ops->reg_mutex);
-       /* copy driver operators */
-       ops->ops = *entry;
-       ops->driver |= DRIVER_LOADED;
-       ops->argsize = argsize;
-
-       /* initialize existing devices if necessary */
-       list_for_each_entry(dev, &ops->dev_list, list) {
-               init_device(dev, ops);
-       }
-       mutex_unlock(&ops->reg_mutex);
-
-       unlock_driver(ops);
-
-       return 0;
+       if (sdev->private_free)
+               sdev->private_free(sdev);
+       kfree(sdev);
 }
 
-
-/*
- * create driver record
- */
-static struct ops_list * create_driver(char *id)
-{
-       struct ops_list *ops;
-
-       ops = kzalloc(sizeof(*ops), GFP_KERNEL);
-       if (ops == NULL)
-               return ops;
-
-       /* set up driver entry */
-       strlcpy(ops->id, id, sizeof(ops->id));
-       mutex_init(&ops->reg_mutex);
-       /*
-        * The ->reg_mutex locking rules are per-driver, so we create
-        * separate per-driver lock classes:
-        */
-       lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);
-
-       ops->driver = DRIVER_EMPTY;
-       INIT_LIST_HEAD(&ops->dev_list);
-       /* lock this instance */
-       ops->used = 1;
-
-       /* register driver entry */
-       mutex_lock(&ops_mutex);
-       list_add_tail(&ops->list, &opslist);
-       num_ops++;
-       mutex_unlock(&ops_mutex);
-
-       return ops;
-}
-
-
 /*
- * unregister the specified driver
+ * register a sequencer device
+ * card = card info
+ * device = device number (if any)
+ * id = id of driver
+ * result = return pointer (NULL allowed if unnecessary)
  */
-int snd_seq_device_unregister_driver(char *id)
+int snd_seq_device_new(struct snd_card *card, int device, const char *id,
+                      int argsize, struct snd_seq_device **result)
 {
-       struct ops_list *ops;
        struct snd_seq_device *dev;
+       int err;
+       static struct snd_device_ops dops = {
+               .dev_free = snd_seq_device_dev_free,
+               .dev_register = snd_seq_device_dev_register,
+               .dev_disconnect = snd_seq_device_dev_disconnect,
+       };
 
-       ops = find_driver(id, 0);
-       if (ops == NULL)
-               return -ENXIO;
-       if (! (ops->driver & DRIVER_LOADED) ||
-           (ops->driver & DRIVER_LOCKED)) {
-               pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
-                          id, ops->driver);
-               unlock_driver(ops);
-               return -EBUSY;
-       }
-
-       /* close and release all devices associated with this driver */
-       mutex_lock(&ops->reg_mutex);
-       ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
-       list_for_each_entry(dev, &ops->dev_list, list) {
-               free_device(dev, ops);
-       }
-
-       ops->driver = 0;
-       if (ops->num_init_devices > 0)
-               pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
-                          ops->num_init_devices);
-       mutex_unlock(&ops->reg_mutex);
-
-       unlock_driver(ops);
+       if (result)
+               *result = NULL;
 
-       /* remove empty driver entries */
-       remove_drivers();
+       if (snd_BUG_ON(!id))
+               return -EINVAL;
 
-       return 0;
-}
+       dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
 
+       /* set up device info */
+       dev->card = card;
+       dev->device = device;
+       dev->id = id;
+       dev->argsize = argsize;
 
-/*
- * remove empty driver entries
- */
-static void remove_drivers(void)
-{
-       struct list_head *head;
-
-       mutex_lock(&ops_mutex);
-       head = opslist.next;
-       while (head != &opslist) {
-               struct ops_list *ops = list_entry(head, struct ops_list, list);
-               if (! (ops->driver & DRIVER_LOADED) &&
-                   ops->used == 0 && ops->num_devices == 0) {
-                       head = head->next;
-                       list_del(&ops->list);
-                       kfree(ops);
-                       num_ops--;
-               } else
-                       head = head->next;
-       }
-       mutex_unlock(&ops_mutex);
-}
+       device_initialize(&dev->dev);
+       dev->dev.parent = &card->card_dev;
+       dev->dev.bus = &snd_seq_bus_type;
+       dev->dev.release = snd_seq_dev_release;
+       dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device);
 
-/*
- * initialize the device - call init_device operator
- */
-static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
-{
-       if (! (ops->driver & DRIVER_LOADED))
-               return 0; /* driver is not loaded yet */
-       if (dev->status != SNDRV_SEQ_DEVICE_FREE)
-               return 0; /* already initialized */
-       if (ops->argsize != dev->argsize) {
-               pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
-                          dev->name, ops->id, ops->argsize, dev->argsize);
-               return -EINVAL;
-       }
-       if (ops->ops.init_device(dev) >= 0) {
-               dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
-               ops->num_init_devices++;
-       } else {
-               pr_err("ALSA: seq: init_device failed: %s: %s\n",
-                          dev->name, dev->id);
+       /* add this device to the list */
+       err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops);
+       if (err < 0) {
+               put_device(&dev->dev);
+               return err;
        }
+       
+       if (result)
+               *result = dev;
 
        return 0;
 }
+EXPORT_SYMBOL(snd_seq_device_new);
 
 /*
- * release the device - call free_device operator
+ * driver registration
  */
-static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
+int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod)
 {
-       int result;
-
-       if (! (ops->driver & DRIVER_LOADED))
-               return 0; /* driver is not loaded yet */
-       if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
-               return 0; /* not registered */
-       if (ops->argsize != dev->argsize) {
-               pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
-                          dev->name, ops->id, ops->argsize, dev->argsize);
+       if (WARN_ON(!drv->driver.name || !drv->id))
                return -EINVAL;
-       }
-       if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {
-               dev->status = SNDRV_SEQ_DEVICE_FREE;
-               dev->driver_data = NULL;
-               ops->num_init_devices--;
-       } else {
-               pr_err("ALSA: seq: free_device failed: %s: %s\n",
-                          dev->name, dev->id);
-       }
-
-       return 0;
+       drv->driver.bus = &snd_seq_bus_type;
+       drv->driver.owner = mod;
+       return driver_register(&drv->driver);
 }
+EXPORT_SYMBOL_GPL(__snd_seq_driver_register);
 
-/*
- * find the matching driver with given id
- */
-static struct ops_list * find_driver(char *id, int create_if_empty)
+void snd_seq_driver_unregister(struct snd_seq_driver *drv)
 {
-       struct ops_list *ops;
-
-       mutex_lock(&ops_mutex);
-       list_for_each_entry(ops, &opslist, list) {
-               if (strcmp(ops->id, id) == 0) {
-                       ops->used++;
-                       mutex_unlock(&ops_mutex);
-                       return ops;
-               }
-       }
-       mutex_unlock(&ops_mutex);
-       if (create_if_empty)
-               return create_driver(id);
-       return NULL;
+       driver_unregister(&drv->driver);
 }
-
-static void unlock_driver(struct ops_list *ops)
-{
-       mutex_lock(&ops_mutex);
-       ops->used--;
-       mutex_unlock(&ops_mutex);
-}
-
+EXPORT_SYMBOL_GPL(snd_seq_driver_unregister);
 
 /*
  * module part
  */
 
-static int __init alsa_seq_device_init(void)
+static int __init seq_dev_proc_init(void)
 {
 #ifdef CONFIG_PROC_FS
        info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
@@ -589,28 +287,29 @@ static int __init alsa_seq_device_init(void)
        return 0;
 }
 
+static int __init alsa_seq_device_init(void)
+{
+       int err;
+
+       err = bus_register(&snd_seq_bus_type);
+       if (err < 0)
+               return err;
+       err = seq_dev_proc_init();
+       if (err < 0)
+               bus_unregister(&snd_seq_bus_type);
+       return err;
+}
+
 static void __exit alsa_seq_device_exit(void)
 {
 #ifdef CONFIG_MODULES
        cancel_work_sync(&autoload_work);
 #endif
-       remove_drivers();
 #ifdef CONFIG_PROC_FS
        snd_info_free_entry(info_entry);
 #endif
-       if (num_ops)
-               pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
+       bus_unregister(&snd_seq_bus_type);
 }
 
-module_init(alsa_seq_device_init)
+subsys_initcall(alsa_seq_device_init)
 module_exit(alsa_seq_device_exit)
-
-EXPORT_SYMBOL(snd_seq_device_load_drivers);
-EXPORT_SYMBOL(snd_seq_device_new);
-EXPORT_SYMBOL(snd_seq_device_register_driver);
-EXPORT_SYMBOL(snd_seq_device_unregister_driver);
-#ifdef CONFIG_MODULES
-EXPORT_SYMBOL(snd_seq_autoload_init);
-EXPORT_SYMBOL(snd_seq_autoload_lock);
-EXPORT_SYMBOL(snd_seq_autoload_unlock);
-#endif
index 5d905d90d504c0d588b62bb856e7314e23488ec0..d3a2ec4f0561e736bf9718c32393be44575bfa49 100644 (file)
@@ -214,11 +214,7 @@ delete_client(void)
 
 static int __init alsa_seq_dummy_init(void)
 {
-       int err;
-       snd_seq_autoload_lock();
-       err = register_client();
-       snd_seq_autoload_unlock();
-       return err;
+       return register_client();
 }
 
 static void __exit alsa_seq_dummy_exit(void)
index 53a403e17c5bba08a755da454dfee3d5829c2cc9..1d5acbe0c08bdf14db4253f95391fa5e99059610 100644 (file)
@@ -33,10 +33,8 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize)
        struct snd_seq_fifo *f;
 
        f = kzalloc(sizeof(*f), GFP_KERNEL);
-       if (f == NULL) {
-               pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n");
+       if (!f)
                return NULL;
-       }
 
        f->pool = snd_seq_pool_new(poolsize);
        if (f->pool == NULL) {
index ba8e4a64e13ee3106ce3f75b693a1f3775e73205..801076687bb16f082a8780125c69e879bdef4019 100644 (file)
@@ -387,10 +387,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
                return 0;
 
        pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
-       if (pool->ptr == NULL) {
-               pr_debug("ALSA: seq: malloc for sequencer events failed\n");
+       if (!pool->ptr)
                return -ENOMEM;
-       }
 
        /* add new cells to the free cell list */
        spin_lock_irqsave(&pool->lock, flags);
@@ -463,10 +461,8 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize)
 
        /* create pool block */
        pool = kzalloc(sizeof(*pool), GFP_KERNEL);
-       if (pool == NULL) {
-               pr_debug("ALSA: seq: malloc failed for pool\n");
+       if (!pool)
                return NULL;
-       }
        spin_lock_init(&pool->lock);
        pool->ptr = NULL;
        pool->free = NULL;
index 68fec776da2619db52163b143551b6e045ce2ee8..5dd0ee2583592e156f5822c2aa56e83c4c41c97d 100644 (file)
@@ -273,8 +273,9 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
 
 /* register new midi synth port */
 static int
-snd_seq_midisynth_register_port(struct snd_seq_device *dev)
+snd_seq_midisynth_probe(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct seq_midisynth_client *client;
        struct seq_midisynth *msynth, *ms;
        struct snd_seq_port_info *port;
@@ -427,8 +428,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
 
 /* release midi synth port */
 static int
-snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
+snd_seq_midisynth_remove(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct seq_midisynth_client *client;
        struct seq_midisynth *msynth;
        struct snd_card *card = dev->card;
@@ -457,24 +459,14 @@ snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
        return 0;
 }
 
+static struct snd_seq_driver seq_midisynth_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .probe = snd_seq_midisynth_probe,
+               .remove = snd_seq_midisynth_remove,
+       },
+       .id = SNDRV_SEQ_DEV_ID_MIDISYNTH,
+       .argsize = 0,
+};
 
-static int __init alsa_seq_midi_init(void)
-{
-       static struct snd_seq_dev_ops ops = {
-               snd_seq_midisynth_register_port,
-               snd_seq_midisynth_unregister_port,
-       };
-       memset(&synths, 0, sizeof(synths));
-       snd_seq_autoload_lock();
-       snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0);
-       snd_seq_autoload_unlock();
-       return 0;
-}
-
-static void __exit alsa_seq_midi_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH);
-}
-
-module_init(alsa_seq_midi_init)
-module_exit(alsa_seq_midi_exit)
+module_snd_seq_driver(seq_midisynth_driver);
index 46ff593f618dc0b75ea66f886e051c035f2aebad..55170a20ae7237246f5560e14c5b5066bb52ba35 100644 (file)
@@ -141,10 +141,8 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
 
        /* create a new port */
        new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
-       if (! new_port) {
-               pr_debug("ALSA: seq: malloc failed for registering client port\n");
+       if (!new_port)
                return NULL;    /* failure, out of memory */
-       }
        /* init port data */
        new_port->addr.client = client->number;
        new_port->addr.port = -1;
index 021b02bc9330f5770fa2ef0072ed844de25b677a..bc1c8488fc2a1508d9572617e9030ba180477fd0 100644 (file)
@@ -59,10 +59,8 @@ struct snd_seq_prioq *snd_seq_prioq_new(void)
        struct snd_seq_prioq *f;
 
        f = kzalloc(sizeof(*f), GFP_KERNEL);
-       if (f == NULL) {
-               pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n");
+       if (!f)
                return NULL;
-       }
        
        spin_lock_init(&f->lock);
        f->head = NULL;
index aad4878cee5579f2556524db0f61a069cc07fef5..a0cda38205b9760bc6e1d1943c8f1deb05ded567 100644 (file)
@@ -111,10 +111,8 @@ static struct snd_seq_queue *queue_new(int owner, int locked)
        struct snd_seq_queue *q;
 
        q = kzalloc(sizeof(*q), GFP_KERNEL);
-       if (q == NULL) {
-               pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n");
+       if (!q)
                return NULL;
-       }
 
        spin_lock_init(&q->owner_lock);
        spin_lock_init(&q->check_lock);
index e73605393eee5351bed9d4472150fd0b63335e5d..186f1611103c5279408c3fa605f62a89f28d537f 100644 (file)
@@ -56,10 +56,8 @@ struct snd_seq_timer *snd_seq_timer_new(void)
        struct snd_seq_timer *tmr;
        
        tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
-       if (tmr == NULL) {
-               pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n");
+       if (!tmr)
                return NULL;
-       }
        spin_lock_init(&tmr->lock);
 
        /* reset setup to defaults */
index 185cec01ee258cceea232209c24b8aa5478b300b..5fc93d00572a5fc4f9ecfa3ba070aa2b3b8efb6f 100644 (file)
@@ -186,7 +186,7 @@ static const struct file_operations snd_fops =
 };
 
 #ifdef CONFIG_SND_DYNAMIC_MINORS
-static int snd_find_free_minor(int type)
+static int snd_find_free_minor(int type, struct snd_card *card, int dev)
 {
        int minor;
 
@@ -209,7 +209,7 @@ static int snd_find_free_minor(int type)
        return -EBUSY;
 }
 #else
-static int snd_kernel_minor(int type, struct snd_card *card, int dev)
+static int snd_find_free_minor(int type, struct snd_card *card, int dev)
 {
        int minor;
 
@@ -237,6 +237,8 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
        }
        if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
                return -EINVAL;
+       if (snd_minors[minor])
+               return -EBUSY;
        return minor;
 }
 #endif
@@ -276,13 +278,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
        preg->private_data = private_data;
        preg->card_ptr = card;
        mutex_lock(&sound_mutex);
-#ifdef CONFIG_SND_DYNAMIC_MINORS
-       minor = snd_find_free_minor(type);
-#else
-       minor = snd_kernel_minor(type, card, dev);
-       if (minor >= 0 && snd_minors[minor])
-               minor = -EBUSY;
-#endif
+       minor = snd_find_free_minor(type, card, dev);
        if (minor < 0) {
                err = minor;
                goto error;
index 490b489d713d4c892af0689d4eafb32cde2131c1..a9a1a047c521ff510949f87ca21c192df9497187 100644 (file)
@@ -774,10 +774,8 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
        if (rtimer)
                *rtimer = NULL;
        timer = kzalloc(sizeof(*timer), GFP_KERNEL);
-       if (timer == NULL) {
-               pr_err("ALSA: timer: cannot allocate\n");
+       if (!timer)
                return -ENOMEM;
-       }
        timer->tmr_class = tid->dev_class;
        timer->card = card;
        timer->tmr_device = tid->device;
index a9f618e06a22bc5f8722932d31e02bfe7fec82b2..fdae5d7f421ff76c119606ca04e909f58f76be0d 100644 (file)
@@ -216,8 +216,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3)
 
 /* ------------------------------ */
 
-static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
+static int snd_opl3_seq_probe(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_opl3 *opl3;
        int client, err;
        char name[32];
@@ -257,8 +258,9 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
        return 0;
 }
 
-static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
+static int snd_opl3_seq_remove(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_opl3 *opl3;
 
        opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
@@ -275,22 +277,14 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
        return 0;
 }
 
-static int __init alsa_opl3_seq_init(void)
-{
-       static struct snd_seq_dev_ops ops =
-       {
-               snd_opl3_seq_new_device,
-               snd_opl3_seq_delete_device
-       };
-
-       return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops,
-                                             sizeof(struct snd_opl3 *));
-}
-
-static void __exit alsa_opl3_seq_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3);
-}
+static struct snd_seq_driver opl3_seq_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .probe = snd_opl3_seq_probe,
+               .remove = snd_opl3_seq_remove,
+       },
+       .id = SNDRV_SEQ_DEV_ID_OPL3,
+       .argsize = sizeof(struct snd_opl3 *),
+};
 
-module_init(alsa_opl3_seq_init)
-module_exit(alsa_opl3_seq_exit)
+module_snd_seq_driver(opl3_seq_driver);
index 99197699c55a63f50bd33f45d454a40f4dd5cf70..03d6202f482931ed4c9aeab5808bec0457aab23a 100644 (file)
@@ -124,8 +124,9 @@ static void snd_opl4_seq_free_port(void *private_data)
        snd_midi_channel_free_set(opl4->chset);
 }
 
-static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
+static int snd_opl4_seq_probe(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_opl4 *opl4;
        int client;
        struct snd_seq_port_callback pcallbacks;
@@ -180,8 +181,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
        return 0;
 }
 
-static int snd_opl4_seq_delete_device(struct snd_seq_device *dev)
+static int snd_opl4_seq_remove(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_opl4 *opl4;
 
        opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
@@ -195,21 +197,14 @@ static int snd_opl4_seq_delete_device(struct snd_seq_device *dev)
        return 0;
 }
 
-static int __init alsa_opl4_synth_init(void)
-{
-       static struct snd_seq_dev_ops ops = {
-               snd_opl4_seq_new_device,
-               snd_opl4_seq_delete_device
-       };
-
-       return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops,
-                                             sizeof(struct snd_opl4 *));
-}
-
-static void __exit alsa_opl4_synth_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4);
-}
+static struct snd_seq_driver opl4_seq_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .probe = snd_opl4_seq_probe,
+               .remove = snd_opl4_seq_remove,
+       },
+       .id = SNDRV_SEQ_DEV_ID_OPL4,
+       .argsize = sizeof(struct snd_opl4 *),
+};
 
-module_init(alsa_opl4_synth_init)
-module_exit(alsa_opl4_synth_exit)
+module_snd_seq_driver(opl4_seq_driver);
index 5cc356db5351d903a7199b233fdfffc2bd8a674e..e061355f535f071f0fd096bfee62fb2702c0c94d 100644 (file)
@@ -166,10 +166,10 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
         * One AMDTP packet can include some frames. In blocking mode, the
         * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
         * depending on its sampling rate. For accurate period interrupt, it's
-        * preferrable to aligh period/buffer sizes to current SYT_INTERVAL.
+        * preferrable to align period/buffer sizes to current SYT_INTERVAL.
         *
-        * TODO: These constraints can be improved with propper rules.
-        * Currently apply LCM of SYT_INTEVALs.
+        * TODO: These constraints can be improved with proper rules.
+        * Currently apply LCM of SYT_INTERVALs.
         */
        err = snd_pcm_hw_constraint_step(runtime, 0,
                                         SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
@@ -270,7 +270,7 @@ static void amdtp_read_s32(struct amdtp_stream *s,
  * @s: the AMDTP stream to configure
  * @format: the format of the ALSA PCM device
  *
- * The sample format must be set after the other paramters (rate/PCM channels/
+ * The sample format must be set after the other parameters (rate/PCM channels/
  * MIDI) and before the stream is started, and must not be changed while the
  * stream is running.
  */
index 2a85e4209f0b74d6f169dd705ffbf6fc9a2d3402..f550808d178416cfd8c67cb9b78722687b2001e5 100644 (file)
@@ -13,7 +13,7 @@
  *
  * Transaction substance:
  *  At first, 6 data exist. Following to the data, parameters for each command
- *  exist. All of the parameters are 32 bit alighed to big endian.
+ *  exist. All of the parameters are 32 bit aligned to big endian.
  *   data[0]:  Length of transaction substance
  *   data[1]:  Transaction version
  *   data[2]:  Sequence number. This is incremented by the device
index 72332dfada9a3f2d089cecd7d257ae0121223a8d..4aa719cad331915bb4e9d34d3ee28fe1253b8514 100644 (file)
@@ -34,8 +34,9 @@ MODULE_LICENSE("GPL");
 /*
  * create a new hardware dependent device for Emu8000
  */
-static int snd_emu8000_new_device(struct snd_seq_device *dev)
+static int snd_emu8000_probe(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_emu8000 *hw;
        struct snd_emux *emu;
 
@@ -93,8 +94,9 @@ static int snd_emu8000_new_device(struct snd_seq_device *dev)
 /*
  * free all resources
  */
-static int snd_emu8000_delete_device(struct snd_seq_device *dev)
+static int snd_emu8000_remove(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_emu8000 *hw;
 
        if (dev->driver_data == NULL)
@@ -114,21 +116,14 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev)
  *  INIT part
  */
 
-static int __init alsa_emu8000_init(void)
-{
-       
-       static struct snd_seq_dev_ops ops = {
-               snd_emu8000_new_device,
-               snd_emu8000_delete_device,
-       };
-       return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU8000, &ops,
-                                             sizeof(struct snd_emu8000*));
-}
-
-static void __exit alsa_emu8000_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000);
-}
-
-module_init(alsa_emu8000_init)
-module_exit(alsa_emu8000_exit)
+static struct snd_seq_driver emu8000_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .probe = snd_emu8000_probe,
+               .remove = snd_emu8000_remove,
+       },
+       .id = SNDRV_SEQ_DEV_ID_EMU8000,
+       .argsize = sizeof(struct snd_emu8000 *),
+};
+
+module_snd_seq_driver(emu8000_driver);
index 607cee4d545ec675cdfebb91ec6802b4555c71fa..b6d19adf8f4111d575c88b235142d6ed0580654f 100644 (file)
@@ -666,7 +666,7 @@ static int opl3_start_note (int dev, int voice, int note, int volume)
        opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data);
 
        data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
-                devc->voc[voice].keyon_byte = data;
+       devc->voc[voice].keyon_byte = data;
        opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data);
        if (voice_mode == 4)
                opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data);
@@ -717,7 +717,7 @@ static void freq_to_fnum    (int freq, int *block, int *fnum)
 
 static void opl3_command    (int io_addr, unsigned int addr, unsigned int val)
 {
-        int i;
+       int i;
 
        /*
         * The original 2-OP synth requires a quite long delay after writing to a
index b47a69026f1b08eee5744bd4649702d87594b3c1..57f7d25a2cd30004446b99659be0943d02d19e3c 100644 (file)
@@ -604,7 +604,7 @@ static void ess_audio_output_block_audio2
        ess_chgmixer (devc, 0x78, 0x03, 0x03);   /* Go */
 
        devc->irq_mode_16 = IMODE_OUTPUT;
-               devc->intr_active_16 = 1;
+       devc->intr_active_16 = 1;
 }
 
 static void ess_audio_output_block
@@ -1183,17 +1183,12 @@ FKS_test (devc);
                        chip = "ES1688";
                }
 
-           printk ( KERN_INFO "ESS chip %s %s%s\n"
-               , chip
-               , ( devc->sbmo.esstype == ESSTYPE_DETECT || devc->sbmo.esstype == ESSTYPE_LIKE20
-                 ? "detected"
-                 : "specified"
-                 )
-               , ( devc->sbmo.esstype == ESSTYPE_LIKE20
-                 ? " (kernel 2.0 compatible)"
-                 : ""
-                 )
-               );
+               printk(KERN_INFO "ESS chip %s %s%s\n", chip,
+                      (devc->sbmo.esstype == ESSTYPE_DETECT ||
+                       devc->sbmo.esstype == ESSTYPE_LIKE20) ?
+                               "detected" : "specified",
+                       devc->sbmo.esstype == ESSTYPE_LIKE20 ?
+                               " (kernel 2.0 compatible)" : "");
 
                sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f);
        } else {
index f139028e85c0dda9f30f9b3406f0e945f5d1bc70..551ee7557b4efb006b9a8ce8f9c7f252b2cb5cd5 100644 (file)
@@ -179,14 +179,14 @@ void sb_dsp_midi_init(sb_devc * devc, struct module *owner)
        {
                printk(KERN_WARNING "Sound Blaster:  failed to allocate MIDI memory.\n");
                sound_unload_mididev(dev);
-                 return;
+               return;
        }
        memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations,
               sizeof(struct midi_operations));
 
        if (owner)
-                       midi_devs[dev]->owner = owner;
-       
+               midi_devs[dev]->owner = owner;
+
        midi_devs[dev]->devc = devc;
 
 
index 9f039831114c2f75e11789e061dd505933f87beb..2226dda0eff0d9e2daf3f907877f20930f4f57ff 100644 (file)
@@ -50,29 +50,24 @@ tmr2ticks(int tmr_value)
 static void
 poll_def_tmr(unsigned long dummy)
 {
+       if (!opened)
+               return;
+       def_tmr.expires = (1) + jiffies;
+       add_timer(&def_tmr);
 
-       if (opened)
-         {
+       if (!tmr_running)
+               return;
 
-                 {
-                         def_tmr.expires = (1) + jiffies;
-                         add_timer(&def_tmr);
-                 }
+       spin_lock(&lock);
+       tmr_ctr++;
+       curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
 
-                 if (tmr_running)
-                   {
-                               spin_lock(&lock);
-                           tmr_ctr++;
-                           curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
-
-                           if (curr_ticks >= next_event_time)
-                             {
-                                     next_event_time = (unsigned long) -1;
-                                     sequencer_timer(0);
-                             }
-                               spin_unlock(&lock);
-                   }
-         }
+       if (curr_ticks >= next_event_time) {
+               next_event_time = (unsigned long) -1;
+               sequencer_timer(0);
+       }
+
+       spin_unlock(&lock);
 }
 
 static void
index 5ee2f17c287c0f316fad46d278b64fd118b2abb3..5bca1a33fed69ee1c7047993f8d6cfc150d9b4b3 100644 (file)
@@ -177,6 +177,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
 { 0x54524123, 0xffffffff, "TR28602",           NULL,           NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e03, 0xffffffff, "TLV320AIC27",       NULL,           NULL },
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
+{ 0x56494120, 0xfffffff0, "VIA1613",           patch_vt1613,   NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
 { 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
 { 0x56494182, 0xffffffff, "VIA1618",           patch_vt1618,   NULL },
index ceaac1c41906992acad253807f1e9b8514b68d75..f4234edb878c7a01ebbc296bf52cb0debb24b087 100644 (file)
@@ -3351,6 +3351,33 @@ static int patch_cm9780(struct snd_ac97 *ac97)
        return 0;
 }
 
+/*
+ * VIA VT1613 codec
+ */
+static const struct snd_kcontrol_new snd_ac97_controls_vt1613[] = {
+AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),
+};
+
+static int patch_vt1613_specific(struct snd_ac97 *ac97)
+{
+       return patch_build_controls(ac97, &snd_ac97_controls_vt1613[0],
+                                   ARRAY_SIZE(snd_ac97_controls_vt1613));
+};
+
+static const struct snd_ac97_build_ops patch_vt1613_ops = {
+       .build_specific = patch_vt1613_specific
+};
+
+static int patch_vt1613(struct snd_ac97 *ac97)
+{
+       ac97->build_ops = &patch_vt1613_ops;
+
+       ac97->flags |= AC97_HAS_NO_VIDEO;
+       ac97->caps |= AC97_BC_HEADPHONE;
+
+       return 0;
+}
+
 /*
  * VIA VT1616 codec
  */
index a40a2b4c8fd7ac8ae992a928e67c00d1c4091473..33b2a0af1b594017959fada0b8d26ec61e43689e 100644 (file)
@@ -1385,8 +1385,8 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
                                        .running)
                             &&  (!chip->codecs[peer_codecs[codec_type].other2]
                                        .running));
-                }
-                if (call_function)
+               }
+               if (call_function)
                        snd_azf3328_ctrl_enable_codecs(chip, enable);
 
                /* ...and adjust clock, too
@@ -2126,7 +2126,8 @@ static struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
 static int
 snd_azf3328_pcm(struct snd_azf3328 *chip)
 {
-enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
+       /* pcm devices */
+       enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS };
 
        struct snd_pcm *pcm;
        int err;
index 1d0f2cad2f5a64e84c37f69ce264445f732c99fd..6cf464d9043d29d8e949d32c4ac33ce54047f7ce 100644 (file)
@@ -2062,7 +2062,7 @@ static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol,
                val = (snd_cmipci_mixer_read(cm, reg.right_reg) >> reg.right_shift) & reg.mask;
                if (reg.invert)
                        val = reg.mask - val;
-                ucontrol->value.integer.value[1] = val;
+               ucontrol->value.integer.value[1] = val;
        }
        spin_unlock_irq(&cm->reg_lock);
        return 0;
index 4c41c903a840b5a6d3f802970b6ced5246b54462..5457d5613f6b46ac79b342282f3380b376f15a28 100644 (file)
@@ -29,8 +29,9 @@ MODULE_LICENSE("GPL");
 /*
  * create a new hardware dependent device for Emu10k1
  */
-static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
+static int snd_emu10k1_synth_probe(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_emux *emux;
        struct snd_emu10k1 *hw;
        struct snd_emu10k1_synth_arg *arg;
@@ -79,8 +80,9 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
        return 0;
 }
 
-static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev)
+static int snd_emu10k1_synth_remove(struct device *_dev)
 {
+       struct snd_seq_device *dev = to_seq_dev(_dev);
        struct snd_emux *emux;
        struct snd_emu10k1 *hw;
        unsigned long flags;
@@ -104,21 +106,14 @@ static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev)
  *  INIT part
  */
 
-static int __init alsa_emu10k1_synth_init(void)
-{
-       
-       static struct snd_seq_dev_ops ops = {
-               snd_emu10k1_synth_new_device,
-               snd_emu10k1_synth_delete_device,
-       };
-       return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, &ops,
-                                             sizeof(struct snd_emu10k1_synth_arg));
-}
-
-static void __exit alsa_emu10k1_synth_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH);
-}
-
-module_init(alsa_emu10k1_synth_init)
-module_exit(alsa_emu10k1_synth_exit)
+static struct snd_seq_driver emu10k1_synth_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .probe = snd_emu10k1_synth_probe,
+               .remove = snd_emu10k1_synth_remove,
+       },
+       .id = SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
+       .argsize = sizeof(struct snd_emu10k1_synth_arg),
+};
+
+module_snd_seq_driver(emu10k1_synth_driver);
index 194f30935e776f3a3f464091176f334e4bdbf2e1..96caaebfc19d256271a38b70dc382d3bc413c8b9 100644 (file)
@@ -4,7 +4,7 @@ snd-hda-tegra-objs := hda_tegra.o
 # for haswell power well
 snd-hda-intel-$(CONFIG_SND_HDA_I915) +=        hda_i915.o
 
-snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
+snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
index 1e7de08e77cbf46729412443591f4d18d103f23c..4cdac3a71caea05c4899b47e40e7fad7274a1282 100644 (file)
@@ -33,30 +33,36 @@ enum {
        DIGBEEP_HZ_MAX = 12000000,      /* 12 KHz */
 };
 
-static void snd_hda_generate_beep(struct work_struct *work)
+/* generate or stop tone */
+static void generate_tone(struct hda_beep *beep, int tone)
 {
-       struct hda_beep *beep =
-               container_of(work, struct hda_beep, beep_work);
        struct hda_codec *codec = beep->codec;
-       int tone;
 
-       if (!beep->enabled)
-               return;
-
-       tone = beep->tone;
        if (tone && !beep->playing) {
                snd_hda_power_up(codec);
+               if (beep->power_hook)
+                       beep->power_hook(beep, true);
                beep->playing = 1;
        }
-       /* generate tone */
        snd_hda_codec_write(codec, beep->nid, 0,
                            AC_VERB_SET_BEEP_CONTROL, tone);
        if (!tone && beep->playing) {
                beep->playing = 0;
+               if (beep->power_hook)
+                       beep->power_hook(beep, false);
                snd_hda_power_down(codec);
        }
 }
 
+static void snd_hda_generate_beep(struct work_struct *work)
+{
+       struct hda_beep *beep =
+               container_of(work, struct hda_beep, beep_work);
+
+       if (beep->enabled)
+               generate_tone(beep, beep->tone);
+}
+
 /* (non-standard) Linear beep tone calculation for IDT/STAC codecs 
  *
  * The tone frequency of beep generator on IDT/STAC codecs is
@@ -130,10 +136,7 @@ static void turn_off_beep(struct hda_beep *beep)
        cancel_work_sync(&beep->beep_work);
        if (beep->playing) {
                /* turn off beep */
-               snd_hda_codec_write(beep->codec, beep->nid, 0,
-                                   AC_VERB_SET_BEEP_CONTROL, 0);
-               beep->playing = 0;
-               snd_hda_power_down(beep->codec);
+               generate_tone(beep, 0);
        }
 }
 
@@ -160,6 +163,7 @@ static int snd_hda_do_attach(struct hda_beep *beep)
        input_dev->name = "HDA Digital PCBeep";
        input_dev->phys = beep->phys;
        input_dev->id.bustype = BUS_PCI;
+       input_dev->dev.parent = &codec->card->card_dev;
 
        input_dev->id.vendor = codec->vendor_id >> 16;
        input_dev->id.product = codec->vendor_id & 0xffff;
@@ -168,7 +172,6 @@ static int snd_hda_do_attach(struct hda_beep *beep)
        input_dev->evbit[0] = BIT_MASK(EV_SND);
        input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
        input_dev->event = snd_hda_beep_event;
-       input_dev->dev.parent = &codec->dev;
        input_set_drvdata(input_dev, beep);
 
        beep->dev = input_dev;
@@ -224,7 +227,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
        if (beep == NULL)
                return -ENOMEM;
        snprintf(beep->phys, sizeof(beep->phys),
-               "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
+               "card%d/codec#%d/beep0", codec->card->number, codec->addr);
        /* enable linear scale */
        snd_hda_codec_write_cache(codec, nid, 0,
                AC_VERB_SET_DIGI_CONVERT_2, 0x01);
index a63b5e077332a94e5a8e29457d2f6818c258ed6d..46524ff7e79e68f7bc23a1d251bef63cd497d187 100644 (file)
@@ -40,6 +40,7 @@ struct hda_beep {
        unsigned int playing:1;
        struct work_struct beep_work; /* scheduled task for beep event */
        struct mutex mutex;
+       void (*power_hook)(struct hda_beep *beep, bool on);
 };
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
new file mode 100644 (file)
index 0000000..1f40ce3
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * HD-audio codec driver binding
+ * Copyright (c) Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/* codec vendor labels */
+struct hda_vendor_id {
+       unsigned int id;
+       const char *name;
+};
+
+static struct hda_vendor_id hda_vendor_ids[] = {
+       { 0x1002, "ATI" },
+       { 0x1013, "Cirrus Logic" },
+       { 0x1057, "Motorola" },
+       { 0x1095, "Silicon Image" },
+       { 0x10de, "Nvidia" },
+       { 0x10ec, "Realtek" },
+       { 0x1102, "Creative" },
+       { 0x1106, "VIA" },
+       { 0x111d, "IDT" },
+       { 0x11c1, "LSI" },
+       { 0x11d4, "Analog Devices" },
+       { 0x13f6, "C-Media" },
+       { 0x14f1, "Conexant" },
+       { 0x17e8, "Chrontel" },
+       { 0x1854, "LG" },
+       { 0x1aec, "Wolfson Microelectronics" },
+       { 0x1af4, "QEMU" },
+       { 0x434d, "C-Media" },
+       { 0x8086, "Intel" },
+       { 0x8384, "SigmaTel" },
+       {} /* terminator */
+};
+
+/*
+ * find a matching codec preset
+ */
+static int hda_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct hda_codec *codec = container_of(dev, struct hda_codec, dev);
+       struct hda_codec_driver *driver =
+               container_of(drv, struct hda_codec_driver, driver);
+       const struct hda_codec_preset *preset;
+       /* check probe_id instead of vendor_id if set */
+       u32 id = codec->probe_id ? codec->probe_id : codec->vendor_id;
+
+       for (preset = driver->preset; preset->id; preset++) {
+               u32 mask = preset->mask;
+
+               if (preset->afg && preset->afg != codec->afg)
+                       continue;
+               if (preset->mfg && preset->mfg != codec->mfg)
+                       continue;
+               if (!mask)
+                       mask = ~0;
+               if (preset->id == (id & mask) &&
+                   (!preset->rev || preset->rev == codec->revision_id)) {
+                       codec->preset = preset;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* reset the codec name from the preset */
+static int codec_refresh_name(struct hda_codec *codec, const char *name)
+{
+       char tmp[16];
+
+       kfree(codec->chip_name);
+       if (!name) {
+               sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
+               name = tmp;
+       }
+       codec->chip_name = kstrdup(name, GFP_KERNEL);
+       return codec->chip_name ? 0 : -ENOMEM;
+}
+
+static int hda_codec_driver_probe(struct device *dev)
+{
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+       struct module *owner = dev->driver->owner;
+       int err;
+
+       if (WARN_ON(!codec->preset))
+               return -EINVAL;
+
+       err = codec_refresh_name(codec, codec->preset->name);
+       if (err < 0)
+               goto error;
+
+       if (!try_module_get(owner)) {
+               err = -EINVAL;
+               goto error;
+       }
+
+       err = codec->preset->patch(codec);
+       if (err < 0)
+               goto error_module;
+
+       err = snd_hda_codec_build_pcms(codec);
+       if (err < 0)
+               goto error_module;
+       err = snd_hda_codec_build_controls(codec);
+       if (err < 0)
+               goto error_module;
+       if (codec->card->registered) {
+               err = snd_card_register(codec->card);
+               if (err < 0)
+                       goto error_module;
+       }
+
+       return 0;
+
+ error_module:
+       module_put(owner);
+
+ error:
+       snd_hda_codec_cleanup_for_unbind(codec);
+       return err;
+}
+
+static int hda_codec_driver_remove(struct device *dev)
+{
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+
+       if (codec->patch_ops.free)
+               codec->patch_ops.free(codec);
+       snd_hda_codec_cleanup_for_unbind(codec);
+       module_put(dev->driver->owner);
+       return 0;
+}
+
+static void hda_codec_driver_shutdown(struct device *dev)
+{
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+
+       if (!pm_runtime_suspended(dev) && codec->patch_ops.reboot_notify)
+               codec->patch_ops.reboot_notify(codec);
+}
+
+int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
+                              struct module *owner)
+{
+       drv->driver.name = name;
+       drv->driver.owner = owner;
+       drv->driver.bus = &snd_hda_bus_type;
+       drv->driver.probe = hda_codec_driver_probe;
+       drv->driver.remove = hda_codec_driver_remove;
+       drv->driver.shutdown = hda_codec_driver_shutdown;
+       drv->driver.pm = &hda_codec_driver_pm;
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(__hda_codec_driver_register);
+
+void hda_codec_driver_unregister(struct hda_codec_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(hda_codec_driver_unregister);
+
+static inline bool codec_probed(struct hda_codec *codec)
+{
+       return device_attach(hda_codec_dev(codec)) > 0 && codec->preset;
+}
+
+/* try to auto-load and bind the codec module */
+static void codec_bind_module(struct hda_codec *codec)
+{
+#ifdef MODULE
+       request_module("snd-hda-codec-id:%08x", codec->vendor_id);
+       if (codec_probed(codec))
+               return;
+       request_module("snd-hda-codec-id:%04x*",
+                      (codec->vendor_id >> 16) & 0xffff);
+       if (codec_probed(codec))
+               return;
+#endif
+}
+
+/* store the codec vendor name */
+static int get_codec_vendor_name(struct hda_codec *codec)
+{
+       const struct hda_vendor_id *c;
+       const char *vendor = NULL;
+       u16 vendor_id = codec->vendor_id >> 16;
+       char tmp[16];
+
+       for (c = hda_vendor_ids; c->id; c++) {
+               if (c->id == vendor_id) {
+                       vendor = c->name;
+                       break;
+               }
+       }
+       if (!vendor) {
+               sprintf(tmp, "Generic %04x", vendor_id);
+               vendor = tmp;
+       }
+       codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
+       if (!codec->vendor_name)
+               return -ENOMEM;
+       return 0;
+}
+
+#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
+/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
+static bool is_likely_hdmi_codec(struct hda_codec *codec)
+{
+       hda_nid_t nid = codec->start_nid;
+       int i;
+
+       for (i = 0; i < codec->num_nodes; i++, nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               switch (get_wcaps_type(wcaps)) {
+               case AC_WID_AUD_IN:
+                       return false; /* HDMI parser supports only HDMI out */
+               case AC_WID_AUD_OUT:
+                       if (!(wcaps & AC_WCAP_DIGITAL))
+                               return false;
+                       break;
+               }
+       }
+       return true;
+}
+#else
+/* no HDMI codec parser support */
+#define is_likely_hdmi_codec(codec)    false
+#endif /* CONFIG_SND_HDA_CODEC_HDMI */
+
+static int codec_bind_generic(struct hda_codec *codec)
+{
+       if (codec->probe_id)
+               return -ENODEV;
+
+       if (is_likely_hdmi_codec(codec)) {
+               codec->probe_id = HDA_CODEC_ID_GENERIC_HDMI;
+#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
+               request_module("snd-hda-codec-hdmi");
+#endif
+               if (codec_probed(codec))
+                       return 0;
+       }
+
+       codec->probe_id = HDA_CODEC_ID_GENERIC;
+#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
+       request_module("snd-hda-codec-generic");
+#endif
+       if (codec_probed(codec))
+               return 0;
+       return -ENODEV;
+}
+
+#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
+#define is_generic_config(codec) \
+       (codec->modelname && !strcmp(codec->modelname, "generic"))
+#else
+#define is_generic_config(codec)       0
+#endif
+
+/**
+ * snd_hda_codec_configure - (Re-)configure the HD-audio codec
+ * @codec: the HDA codec
+ *
+ * Start parsing of the given codec tree and (re-)initialize the whole
+ * patch instance.
+ *
+ * Returns 0 if successful or a negative error code.
+ */
+int snd_hda_codec_configure(struct hda_codec *codec)
+{
+       int err;
+
+       if (!codec->vendor_name) {
+               err = get_codec_vendor_name(codec);
+               if (err < 0)
+                       return err;
+       }
+
+       if (is_generic_config(codec))
+               codec->probe_id = HDA_CODEC_ID_GENERIC;
+       else
+               codec->probe_id = 0;
+
+       err = device_add(hda_codec_dev(codec));
+       if (err < 0)
+               return err;
+
+       if (!codec->preset)
+               codec_bind_module(codec);
+       if (!codec->preset) {
+               err = codec_bind_generic(codec);
+               if (err < 0) {
+                       codec_err(codec, "Unable to bind the codec\n");
+                       goto error;
+               }
+       }
+
+       /* audio codec should override the mixer name */
+       if (codec->afg || !*codec->card->mixername)
+               snprintf(codec->card->mixername,
+                        sizeof(codec->card->mixername),
+                        "%s %s", codec->vendor_name, codec->chip_name);
+       return 0;
+
+ error:
+       device_del(hda_codec_dev(codec));
+       return err;
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
+
+/*
+ * bus registration
+ */
+struct bus_type snd_hda_bus_type = {
+       .name = "hdaudio",
+       .match = hda_bus_match,
+};
+
+static int __init hda_codec_init(void)
+{
+       return bus_register(&snd_hda_bus_type);
+}
+
+static void __exit hda_codec_exit(void)
+{
+       bus_unregister(&snd_hda_bus_type);
+}
+
+module_init(hda_codec_init);
+module_exit(hda_codec_exit);
index 2fe86d2e1b09dfc6f5d8f095a3fc3ad4792680f5..7e38d6f7314b7d1830e2dee1d0aa5862ff08557d 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/async.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include <sound/asoundef.h>
 #define CREATE_TRACE_POINTS
 #include "hda_trace.h"
 
-/*
- * vendor / preset table
- */
-
-struct hda_vendor_id {
-       unsigned int id;
-       const char *name;
-};
-
-/* codec vendor labels */
-static struct hda_vendor_id hda_vendor_ids[] = {
-       { 0x1002, "ATI" },
-       { 0x1013, "Cirrus Logic" },
-       { 0x1057, "Motorola" },
-       { 0x1095, "Silicon Image" },
-       { 0x10de, "Nvidia" },
-       { 0x10ec, "Realtek" },
-       { 0x1102, "Creative" },
-       { 0x1106, "VIA" },
-       { 0x111d, "IDT" },
-       { 0x11c1, "LSI" },
-       { 0x11d4, "Analog Devices" },
-       { 0x13f6, "C-Media" },
-       { 0x14f1, "Conexant" },
-       { 0x17e8, "Chrontel" },
-       { 0x1854, "LG" },
-       { 0x1aec, "Wolfson Microelectronics" },
-       { 0x1af4, "QEMU" },
-       { 0x434d, "C-Media" },
-       { 0x8086, "Intel" },
-       { 0x8384, "SigmaTel" },
-       {} /* terminator */
-};
-
-static DEFINE_MUTEX(preset_mutex);
-static LIST_HEAD(hda_preset_tables);
-
-/**
- * snd_hda_add_codec_preset - Add a codec preset to the chain
- * @preset: codec preset table to add
- */
-int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
-{
-       mutex_lock(&preset_mutex);
-       list_add_tail(&preset->list, &hda_preset_tables);
-       mutex_unlock(&preset_mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset);
-
-/**
- * snd_hda_delete_codec_preset - Delete a codec preset from the chain
- * @preset: codec preset table to delete
- */
-int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
-{
-       mutex_lock(&preset_mutex);
-       list_del(&preset->list);
-       mutex_unlock(&preset_mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset);
-
 #ifdef CONFIG_PM
-#define codec_in_pm(codec)     ((codec)->in_pm)
-static void hda_power_work(struct work_struct *work);
-static void hda_keep_power_on(struct hda_codec *codec);
-#define hda_codec_is_power_on(codec)   ((codec)->power_on)
-
-static void hda_call_pm_notify(struct hda_codec *codec, bool power_up)
-{
-       struct hda_bus *bus = codec->bus;
-
-       if ((power_up && codec->pm_up_notified) ||
-           (!power_up && !codec->pm_up_notified))
-               return;
-       if (bus->ops.pm_notify)
-               bus->ops.pm_notify(bus, power_up);
-       codec->pm_up_notified = power_up;
-}
-
+#define codec_in_pm(codec)     atomic_read(&(codec)->in_pm)
+#define hda_codec_is_power_on(codec) \
+       (!pm_runtime_suspended(hda_codec_dev(codec)))
 #else
 #define codec_in_pm(codec)     0
-static inline void hda_keep_power_on(struct hda_codec *codec) {}
 #define hda_codec_is_power_on(codec)   1
-#define hda_call_pm_notify(codec, state) {}
 #endif
 
 /**
@@ -758,14 +681,11 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
        struct hda_bus_unsolicited *unsol;
        unsigned int wp;
 
-       if (!bus || !bus->workq)
+       if (!bus)
                return 0;
 
        trace_hda_unsol_event(bus, res, res_ex);
-       unsol = bus->unsol;
-       if (!unsol)
-               return 0;
-
+       unsol = &bus->unsol;
        wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE;
        unsol->wp = wp;
 
@@ -773,7 +693,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
        unsol->queue[wp] = res;
        unsol->queue[wp + 1] = res_ex;
 
-       queue_work(bus->workq, &unsol->work);
+       schedule_work(&unsol->work);
 
        return 0;
 }
@@ -784,9 +704,8 @@ EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event);
  */
 static void process_unsol_events(struct work_struct *work)
 {
-       struct hda_bus_unsolicited *unsol =
-               container_of(work, struct hda_bus_unsolicited, work);
-       struct hda_bus *bus = unsol->bus;
+       struct hda_bus *bus = container_of(work, struct hda_bus, unsol.work);
+       struct hda_bus_unsolicited *unsol = &bus->unsol;
        struct hda_codec *codec;
        unsigned int rp, caddr, res;
 
@@ -804,27 +723,6 @@ static void process_unsol_events(struct work_struct *work)
        }
 }
 
-/*
- * initialize unsolicited queue
- */
-static int init_unsol_queue(struct hda_bus *bus)
-{
-       struct hda_bus_unsolicited *unsol;
-
-       if (bus->unsol) /* already initialized */
-               return 0;
-
-       unsol = kzalloc(sizeof(*unsol), GFP_KERNEL);
-       if (!unsol) {
-               dev_err(bus->card->dev, "can't allocate unsolicited queue\n");
-               return -ENOMEM;
-       }
-       INIT_WORK(&unsol->work, process_unsol_events);
-       unsol->bus = bus;
-       bus->unsol = unsol;
-       return 0;
-}
-
 /*
  * destructor
  */
@@ -834,14 +732,9 @@ static void snd_hda_bus_free(struct hda_bus *bus)
                return;
 
        WARN_ON(!list_empty(&bus->codec_list));
-       if (bus->workq)
-               flush_workqueue(bus->workq);
-       kfree(bus->unsol);
+       cancel_work_sync(&bus->unsol.work);
        if (bus->ops.private_free)
                bus->ops.private_free(bus);
-       if (bus->workq)
-               destroy_workqueue(bus->workq);
-
        kfree(bus);
 }
 
@@ -861,14 +754,12 @@ static int snd_hda_bus_dev_disconnect(struct snd_device *device)
 /**
  * snd_hda_bus_new - create a HDA bus
  * @card: the card entry
- * @temp: the template for hda_bus information
  * @busp: the pointer to store the created bus instance
  *
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hda_bus_new(struct snd_card *card,
-                             const struct hda_bus_template *temp,
-                             struct hda_bus **busp)
+                   struct hda_bus **busp)
 {
        struct hda_bus *bus;
        int err;
@@ -877,40 +768,18 @@ int snd_hda_bus_new(struct snd_card *card,
                .dev_free = snd_hda_bus_dev_free,
        };
 
-       if (snd_BUG_ON(!temp))
-               return -EINVAL;
-       if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response))
-               return -EINVAL;
-
        if (busp)
                *busp = NULL;
 
        bus = kzalloc(sizeof(*bus), GFP_KERNEL);
-       if (bus == NULL) {
-               dev_err(card->dev, "can't allocate struct hda_bus\n");
+       if (!bus)
                return -ENOMEM;
-       }
 
        bus->card = card;
-       bus->private_data = temp->private_data;
-       bus->pci = temp->pci;
-       bus->modelname = temp->modelname;
-       bus->power_save = temp->power_save;
-       bus->ops = temp->ops;
-
        mutex_init(&bus->cmd_mutex);
        mutex_init(&bus->prepare_mutex);
        INIT_LIST_HEAD(&bus->codec_list);
-
-       snprintf(bus->workq_name, sizeof(bus->workq_name),
-                "hd-audio%d", card->number);
-       bus->workq = create_singlethread_workqueue(bus->workq_name);
-       if (!bus->workq) {
-               dev_err(card->dev, "cannot create workqueue %s\n",
-                          bus->workq_name);
-               kfree(bus);
-               return -ENOMEM;
-       }
+       INIT_WORK(&bus->unsol.work, process_unsol_events);
 
        err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops);
        if (err < 0) {
@@ -923,111 +792,6 @@ int snd_hda_bus_new(struct snd_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_hda_bus_new);
 
-#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
-#define is_generic_config(codec) \
-       (codec->modelname && !strcmp(codec->modelname, "generic"))
-#else
-#define is_generic_config(codec)       0
-#endif
-
-#ifdef MODULE
-#define HDA_MODREQ_MAX_COUNT   2       /* two request_modules()'s */
-#else
-#define HDA_MODREQ_MAX_COUNT   0       /* all presets are statically linked */
-#endif
-
-/*
- * find a matching codec preset
- */
-static const struct hda_codec_preset *
-find_codec_preset(struct hda_codec *codec)
-{
-       struct hda_codec_preset_list *tbl;
-       const struct hda_codec_preset *preset;
-       unsigned int mod_requested = 0;
-
- again:
-       mutex_lock(&preset_mutex);
-       list_for_each_entry(tbl, &hda_preset_tables, list) {
-               if (!try_module_get(tbl->owner)) {
-                       codec_err(codec, "cannot module_get\n");
-                       continue;
-               }
-               for (preset = tbl->preset; preset->id; preset++) {
-                       u32 mask = preset->mask;
-                       if (preset->afg && preset->afg != codec->afg)
-                               continue;
-                       if (preset->mfg && preset->mfg != codec->mfg)
-                               continue;
-                       if (!mask)
-                               mask = ~0;
-                       if (preset->id == (codec->vendor_id & mask) &&
-                           (!preset->rev ||
-                            preset->rev == codec->revision_id)) {
-                               mutex_unlock(&preset_mutex);
-                               codec->owner = tbl->owner;
-                               return preset;
-                       }
-               }
-               module_put(tbl->owner);
-       }
-       mutex_unlock(&preset_mutex);
-
-       if (mod_requested < HDA_MODREQ_MAX_COUNT) {
-               if (!mod_requested)
-                       request_module("snd-hda-codec-id:%08x",
-                                      codec->vendor_id);
-               else
-                       request_module("snd-hda-codec-id:%04x*",
-                                      (codec->vendor_id >> 16) & 0xffff);
-               mod_requested++;
-               goto again;
-       }
-       return NULL;
-}
-
-/*
- * get_codec_name - store the codec name
- */
-static int get_codec_name(struct hda_codec *codec)
-{
-       const struct hda_vendor_id *c;
-       const char *vendor = NULL;
-       u16 vendor_id = codec->vendor_id >> 16;
-       char tmp[16];
-
-       if (codec->vendor_name)
-               goto get_chip_name;
-
-       for (c = hda_vendor_ids; c->id; c++) {
-               if (c->id == vendor_id) {
-                       vendor = c->name;
-                       break;
-               }
-       }
-       if (!vendor) {
-               sprintf(tmp, "Generic %04x", vendor_id);
-               vendor = tmp;
-       }
-       codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
-       if (!codec->vendor_name)
-               return -ENOMEM;
-
- get_chip_name:
-       if (codec->chip_name)
-               return 0;
-
-       if (codec->preset && codec->preset->name)
-               codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL);
-       else {
-               sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
-               codec->chip_name = kstrdup(tmp, GFP_KERNEL);
-       }
-       if (!codec->chip_name)
-               return -ENOMEM;
-       return 0;
-}
-
 /*
  * look for an AFG and MFG nodes
  */
@@ -1290,8 +1054,8 @@ static void hda_jackpoll_work(struct work_struct *work)
        if (!codec->jackpoll_interval)
                return;
 
-       queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
-                          codec->jackpoll_interval);
+       schedule_delayed_work(&codec->jackpoll_work,
+                             codec->jackpoll_interval);
 }
 
 static void init_hda_cache(struct hda_cache_rec *cache,
@@ -1339,54 +1103,92 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
 }
 
 /*
- * Dynamic symbol binding for the codec parsers
+ * PCM device
  */
+static void release_pcm(struct kref *kref)
+{
+       struct hda_pcm *pcm = container_of(kref, struct hda_pcm, kref);
 
-#define load_parser(codec, sym) \
-       ((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym))
+       if (pcm->pcm)
+               snd_device_free(pcm->codec->card, pcm->pcm);
+       clear_bit(pcm->device, pcm->codec->bus->pcm_dev_bits);
+       kfree(pcm->name);
+       kfree(pcm);
+}
 
-static void unload_parser(struct hda_codec *codec)
+void snd_hda_codec_pcm_put(struct hda_pcm *pcm)
 {
-       if (codec->parser)
-               symbol_put_addr(codec->parser);
-       codec->parser = NULL;
+       kref_put(&pcm->kref, release_pcm);
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_put);
+
+struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
+                                     const char *fmt, ...)
+{
+       struct hda_pcm *pcm;
+       va_list args;
+
+       va_start(args, fmt);
+       pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return NULL;
+
+       pcm->codec = codec;
+       kref_init(&pcm->kref);
+       pcm->name = kvasprintf(GFP_KERNEL, fmt, args);
+       if (!pcm->name) {
+               kfree(pcm);
+               return NULL;
+       }
+
+       list_add_tail(&pcm->list, &codec->pcm_list_head);
+       return pcm;
 }
+EXPORT_SYMBOL_GPL(snd_hda_codec_pcm_new);
 
 /*
  * codec destructor
  */
-static void snd_hda_codec_free(struct hda_codec *codec)
+static void codec_release_pcms(struct hda_codec *codec)
+{
+       struct hda_pcm *pcm, *n;
+
+       list_for_each_entry_safe(pcm, n, &codec->pcm_list_head, list) {
+               list_del_init(&pcm->list);
+               if (pcm->pcm)
+                       snd_device_disconnect(codec->card, pcm->pcm);
+               snd_hda_codec_pcm_put(pcm);
+       }
+}
+
+void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
 {
-       if (!codec)
-               return;
        cancel_delayed_work_sync(&codec->jackpoll_work);
+       if (!codec->in_freeing)
+               snd_hda_ctls_clear(codec);
+       codec_release_pcms(codec);
+       snd_hda_detach_beep_device(codec);
+       memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
        snd_hda_jack_tbl_clear(codec);
-       free_init_pincfgs(codec);
-#ifdef CONFIG_PM
-       cancel_delayed_work(&codec->power_work);
-       flush_workqueue(codec->bus->workq);
-#endif
-       list_del(&codec->list);
-       snd_array_free(&codec->mixers);
-       snd_array_free(&codec->nids);
+       codec->proc_widget_hook = NULL;
+       codec->spec = NULL;
+
+       free_hda_cache(&codec->amp_cache);
+       free_hda_cache(&codec->cmd_cache);
+       init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
+       init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
+
+       /* free only driver_pins so that init_pins + user_pins are restored */
+       snd_array_free(&codec->driver_pins);
        snd_array_free(&codec->cvt_setups);
        snd_array_free(&codec->spdif_out);
+       snd_array_free(&codec->verbs);
+       codec->preset = NULL;
+       codec->slave_dig_outs = NULL;
+       codec->spdif_status_reset = 0;
+       snd_array_free(&codec->mixers);
+       snd_array_free(&codec->nids);
        remove_conn_list(codec);
-       codec->bus->caddr_tbl[codec->addr] = NULL;
-       if (codec->patch_ops.free)
-               codec->patch_ops.free(codec);
-       hda_call_pm_notify(codec, false); /* cancel leftover refcounts */
-       snd_hda_sysfs_clear(codec);
-       unload_parser(codec);
-       module_put(codec->owner);
-       free_hda_cache(&codec->amp_cache);
-       free_hda_cache(&codec->cmd_cache);
-       kfree(codec->vendor_name);
-       kfree(codec->chip_name);
-       kfree(codec->modelname);
-       kfree(codec->wcaps);
-       codec->bus->num_codecs--;
-       put_device(&codec->dev);
 }
 
 static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
@@ -1398,11 +1200,12 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
 static int snd_hda_codec_dev_register(struct snd_device *device)
 {
        struct hda_codec *codec = device->device_data;
-       int err = device_add(&codec->dev);
 
-       if (err < 0)
-               return err;
        snd_hda_register_beep_device(codec);
+       if (device_is_registered(hda_codec_dev(codec)))
+               pm_runtime_enable(hda_codec_dev(codec));
+       /* it was powered up in snd_hda_codec_new(), now all done */
+       snd_hda_power_down(codec);
        return 0;
 }
 
@@ -1411,20 +1214,37 @@ static int snd_hda_codec_dev_disconnect(struct snd_device *device)
        struct hda_codec *codec = device->device_data;
 
        snd_hda_detach_beep_device(codec);
-       device_del(&codec->dev);
        return 0;
 }
 
 static int snd_hda_codec_dev_free(struct snd_device *device)
 {
-       snd_hda_codec_free(device->device_data);
+       struct hda_codec *codec = device->device_data;
+
+       codec->in_freeing = 1;
+       if (device_is_registered(hda_codec_dev(codec)))
+               device_del(hda_codec_dev(codec));
+       put_device(hda_codec_dev(codec));
        return 0;
 }
 
-/* just free the container */
 static void snd_hda_codec_dev_release(struct device *dev)
 {
-       kfree(container_of(dev, struct hda_codec, dev));
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+
+       free_init_pincfgs(codec);
+       list_del(&codec->list);
+       codec->bus->caddr_tbl[codec->addr] = NULL;
+       clear_bit(codec->addr, &codec->bus->codec_powered);
+       snd_hda_sysfs_clear(codec);
+       free_hda_cache(&codec->amp_cache);
+       free_hda_cache(&codec->cmd_cache);
+       kfree(codec->vendor_name);
+       kfree(codec->chip_name);
+       kfree(codec->modelname);
+       kfree(codec->wcaps);
+       codec->bus->num_codecs--;
+       kfree(codec);
 }
 
 /**
@@ -1435,11 +1255,11 @@ static void snd_hda_codec_dev_release(struct device *dev)
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hda_codec_new(struct hda_bus *bus,
-                               unsigned int codec_addr,
-                               struct hda_codec **codecp)
+int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
+                     unsigned int codec_addr, struct hda_codec **codecp)
 {
        struct hda_codec *codec;
+       struct device *dev;
        char component[31];
        hda_nid_t fg;
        int err;
@@ -1455,28 +1275,28 @@ int snd_hda_codec_new(struct hda_bus *bus,
                return -EINVAL;
 
        if (bus->caddr_tbl[codec_addr]) {
-               dev_err(bus->card->dev,
+               dev_err(card->dev,
                        "address 0x%x is already occupied\n",
                        codec_addr);
                return -EBUSY;
        }
 
        codec = kzalloc(sizeof(*codec), GFP_KERNEL);
-       if (codec == NULL) {
-               dev_err(bus->card->dev, "can't allocate struct hda_codec\n");
+       if (!codec)
                return -ENOMEM;
-       }
 
-       device_initialize(&codec->dev);
-       codec->dev.parent = &bus->card->card_dev;
-       codec->dev.class = sound_class;
-       codec->dev.release = snd_hda_codec_dev_release;
-       codec->dev.groups = snd_hda_dev_attr_groups;
-       dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number,
-                    codec_addr);
-       dev_set_drvdata(&codec->dev, codec); /* for sysfs */
+       dev = hda_codec_dev(codec);
+       device_initialize(dev);
+       dev->parent = card->dev;
+       dev->bus = &snd_hda_bus_type;
+       dev->release = snd_hda_codec_dev_release;
+       dev->groups = snd_hda_dev_attr_groups;
+       dev_set_name(dev, "hdaudioC%dD%d", card->number, codec_addr);
+       dev_set_drvdata(dev, codec); /* for sysfs */
+       device_enable_async_suspend(dev);
 
        codec->bus = bus;
+       codec->card = card;
        codec->addr = codec_addr;
        mutex_init(&codec->spdif_mutex);
        mutex_init(&codec->control_mutex);
@@ -1492,19 +1312,20 @@ int snd_hda_codec_new(struct hda_bus *bus,
        snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16);
        snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8);
        INIT_LIST_HEAD(&codec->conn_list);
+       INIT_LIST_HEAD(&codec->pcm_list_head);
 
        INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
        codec->depop_delay = -1;
        codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
 
 #ifdef CONFIG_PM
-       spin_lock_init(&codec->power_lock);
-       INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
        /* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
-        * the caller has to power down appropriatley after initialization
-        * phase.
+        * it's powered down later in snd_hda_codec_dev_register().
         */
-       hda_keep_power_on(codec);
+       set_bit(codec->addr, &bus->codec_powered);
+       pm_runtime_set_active(hda_codec_dev(codec));
+       pm_runtime_get_noresume(hda_codec_dev(codec));
+       codec->power_jiffies = jiffies;
 #endif
 
        snd_hda_sysfs_init(codec);
@@ -1537,17 +1358,15 @@ int snd_hda_codec_new(struct hda_bus *bus,
 
        setup_fg_nodes(codec);
        if (!codec->afg && !codec->mfg) {
-               dev_err(bus->card->dev, "no AFG or MFG node found\n");
+               codec_err(codec, "no AFG or MFG node found\n");
                err = -ENODEV;
                goto error;
        }
 
        fg = codec->afg ? codec->afg : codec->mfg;
        err = read_widget_caps(codec, fg);
-       if (err < 0) {
-               dev_err(bus->card->dev, "cannot malloc\n");
+       if (err < 0)
                goto error;
-       }
        err = read_pin_defaults(codec);
        if (err < 0)
                goto error;
@@ -1564,11 +1383,6 @@ int snd_hda_codec_new(struct hda_bus *bus,
 #endif
        codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
                                        AC_PWRST_EPSS);
-#ifdef CONFIG_PM
-       if (!codec->d3_stop_clk || !codec->epss)
-               bus->power_keep_link_on = 1;
-#endif
-
 
        /* power-up all before initialization */
        hda_set_power_state(codec, AC_PWRST_D0);
@@ -1579,9 +1393,9 @@ int snd_hda_codec_new(struct hda_bus *bus,
 
        sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id,
                codec->subsystem_id, codec->revision_id);
-       snd_component_add(codec->bus->card, component);
+       snd_component_add(card, component);
 
-       err = snd_device_new(bus->card, SNDRV_DEV_CODEC, codec, &dev_ops);
+       err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops);
        if (err < 0)
                goto error;
 
@@ -1590,7 +1404,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
        return 0;
 
  error:
-       snd_hda_codec_free(codec);
+       put_device(hda_codec_dev(codec));
        return err;
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_new);
@@ -1613,10 +1427,8 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
        kfree(codec->wcaps);
        fg = codec->afg ? codec->afg : codec->mfg;
        err = read_widget_caps(codec, fg);
-       if (err < 0) {
-               codec_err(codec, "cannot malloc\n");
+       if (err < 0)
                return err;
-       }
 
        snd_array_free(&codec->init_pins);
        err = read_pin_defaults(codec);
@@ -1625,98 +1437,6 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets);
 
-
-#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
-/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
-static bool is_likely_hdmi_codec(struct hda_codec *codec)
-{
-       hda_nid_t nid = codec->start_nid;
-       int i;
-
-       for (i = 0; i < codec->num_nodes; i++, nid++) {
-               unsigned int wcaps = get_wcaps(codec, nid);
-               switch (get_wcaps_type(wcaps)) {
-               case AC_WID_AUD_IN:
-                       return false; /* HDMI parser supports only HDMI out */
-               case AC_WID_AUD_OUT:
-                       if (!(wcaps & AC_WCAP_DIGITAL))
-                               return false;
-                       break;
-               }
-       }
-       return true;
-}
-#else
-/* no HDMI codec parser support */
-#define is_likely_hdmi_codec(codec)    false
-#endif /* CONFIG_SND_HDA_CODEC_HDMI */
-
-/**
- * snd_hda_codec_configure - (Re-)configure the HD-audio codec
- * @codec: the HDA codec
- *
- * Start parsing of the given codec tree and (re-)initialize the whole
- * patch instance.
- *
- * Returns 0 if successful or a negative error code.
- */
-int snd_hda_codec_configure(struct hda_codec *codec)
-{
-       int (*patch)(struct hda_codec *) = NULL;
-       int err;
-
-       codec->preset = find_codec_preset(codec);
-       if (!codec->vendor_name || !codec->chip_name) {
-               err = get_codec_name(codec);
-               if (err < 0)
-                       return err;
-       }
-
-       if (!is_generic_config(codec) && codec->preset)
-               patch = codec->preset->patch;
-       if (!patch) {
-               unload_parser(codec); /* to be sure */
-               if (is_likely_hdmi_codec(codec)) {
-#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
-                       patch = load_parser(codec, snd_hda_parse_hdmi_codec);
-#elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI)
-                       patch = snd_hda_parse_hdmi_codec;
-#endif
-               }
-               if (!patch) {
-#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
-                       patch = load_parser(codec, snd_hda_parse_generic_codec);
-#elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC)
-                       patch = snd_hda_parse_generic_codec;
-#endif
-               }
-               if (!patch) {
-                       codec_err(codec, "No codec parser is available\n");
-                       return -ENODEV;
-               }
-       }
-
-       err = patch(codec);
-       if (err < 0) {
-               unload_parser(codec);
-               return err;
-       }
-
-       if (codec->patch_ops.unsol_event) {
-               err = init_unsol_queue(codec->bus);
-               if (err < 0)
-                       return err;
-       }
-
-       /* audio codec should override the mixer name */
-       if (codec->afg || !*codec->bus->card->mixername)
-               snprintf(codec->bus->card->mixername,
-                        sizeof(codec->bus->card->mixername),
-                        "%s %s", codec->vendor_name, codec->chip_name);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
-
 /* update the stream-id if changed */
 static void update_pcm_stream_id(struct hda_codec *codec,
                                 struct hda_cvt_setup *p, hda_nid_t nid,
@@ -1782,6 +1502,8 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
        if (!p)
                return;
 
+       if (codec->patch_ops.stream_pm)
+               codec->patch_ops.stream_pm(codec, nid, true);
        if (codec->pcm_format_first)
                update_pcm_format(codec, p, nid, format);
        update_pcm_stream_id(codec, p, nid, stream_tag, channel_id);
@@ -1850,6 +1572,8 @@ static void really_cleanup_stream(struct hda_codec *codec,
 );
        memset(q, 0, sizeof(*q));
        q->nid = nid;
+       if (codec->patch_ops.stream_pm)
+               codec->patch_ops.stream_pm(codec, nid, false);
 }
 
 /* clean up the all conflicting obsolete streams */
@@ -2192,11 +1916,10 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read);
 
 static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
                            int direction, int idx, int mask, int val,
-                           bool init_only)
+                           bool init_only, bool cache_only)
 {
        struct hda_amp_info *info;
        unsigned int caps;
-       unsigned int cache_only;
 
        if (snd_BUG_ON(mask & ~0xff))
                mask &= 0xff;
@@ -2214,7 +1937,7 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
                return 0;
        }
        info->vol[ch] = val;
-       cache_only = info->head.dirty = codec->cached_write;
+       info->head.dirty |= cache_only;
        caps = info->amp_caps;
        mutex_unlock(&codec->hash_mutex);
        if (!cache_only)
@@ -2238,7 +1961,8 @@ static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
 int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
                             int direction, int idx, int mask, int val)
 {
-       return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false);
+       return codec_amp_update(codec, nid, ch, direction, idx, mask, val,
+                               false, codec->cached_write);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
 
@@ -2285,7 +2009,8 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo);
 int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
                           int dir, int idx, int mask, int val)
 {
-       return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true);
+       return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true,
+                               codec->cached_write);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
 
@@ -2427,8 +2152,8 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
        maxval = get_amp_max_value(codec, nid, dir, 0);
        if (val > maxval)
                val = maxval;
-       return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
-                                       HDA_AMP_VOLMASK, val);
+       return codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val,
+                               false, !hda_codec_is_power_on(codec));
 }
 
 /**
@@ -2478,14 +2203,12 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change = 0;
 
-       snd_hda_power_up(codec);
        if (chs & 1) {
                change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
                valp++;
        }
        if (chs & 2)
                change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
-       snd_hda_power_down(codec);
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
@@ -2572,7 +2295,7 @@ find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx)
        if (snd_BUG_ON(strlen(name) >= sizeof(id.name)))
                return NULL;
        strcpy(id.name, name);
-       return snd_ctl_find_id(codec->bus->card, &id);
+       return snd_ctl_find_id(codec->card, &id);
 }
 
 /**
@@ -2636,7 +2359,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
                nid = kctl->id.subdevice & 0xffff;
        if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG))
                kctl->id.subdevice = 0;
-       err = snd_ctl_add(codec->bus->card, kctl);
+       err = snd_ctl_add(codec->card, kctl);
        if (err < 0)
                return err;
        item = snd_array_new(&codec->mixers);
@@ -2689,7 +2412,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
        int i;
        struct hda_nid_item *items = codec->mixers.list;
        for (i = 0; i < codec->mixers.used; i++)
-               snd_ctl_remove(codec->bus->card, items[i].kctl);
+               snd_ctl_remove(codec->card, items[i].kctl);
        snd_array_free(&codec->mixers);
        snd_array_free(&codec->nids);
 }
@@ -2713,9 +2436,8 @@ int snd_hda_lock_devices(struct hda_bus *bus)
                goto err_clear;
 
        list_for_each_entry(codec, &bus->codec_list, list) {
-               int pcm;
-               for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-                       struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+               struct hda_pcm *cpcm;
+               list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
                        if (!cpcm->pcm)
                                continue;
                        if (cpcm->pcm->streams[0].substream_opened ||
@@ -2742,7 +2464,6 @@ void snd_hda_unlock_devices(struct hda_bus *bus)
 {
        struct snd_card *card = bus->card;
 
-       card = bus->card;
        spin_lock(&card->files_lock);
        card->shutdown = 0;
        spin_unlock(&card->files_lock);
@@ -2762,51 +2483,13 @@ EXPORT_SYMBOL_GPL(snd_hda_unlock_devices);
 int snd_hda_codec_reset(struct hda_codec *codec)
 {
        struct hda_bus *bus = codec->bus;
-       struct snd_card *card = bus->card;
-       int i;
 
        if (snd_hda_lock_devices(bus) < 0)
                return -EBUSY;
 
        /* OK, let it free */
-       cancel_delayed_work_sync(&codec->jackpoll_work);
-#ifdef CONFIG_PM
-       cancel_delayed_work_sync(&codec->power_work);
-       flush_workqueue(bus->workq);
-#endif
-       snd_hda_ctls_clear(codec);
-       /* release PCMs */
-       for (i = 0; i < codec->num_pcms; i++) {
-               if (codec->pcm_info[i].pcm) {
-                       snd_device_free(card, codec->pcm_info[i].pcm);
-                       clear_bit(codec->pcm_info[i].device,
-                                 bus->pcm_dev_bits);
-               }
-       }
-       snd_hda_detach_beep_device(codec);
-       if (codec->patch_ops.free)
-               codec->patch_ops.free(codec);
-       memset(&codec->patch_ops, 0, sizeof(codec->patch_ops));
-       snd_hda_jack_tbl_clear(codec);
-       codec->proc_widget_hook = NULL;
-       codec->spec = NULL;
-       free_hda_cache(&codec->amp_cache);
-       free_hda_cache(&codec->cmd_cache);
-       init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
-       init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
-       /* free only driver_pins so that init_pins + user_pins are restored */
-       snd_array_free(&codec->driver_pins);
-       snd_array_free(&codec->cvt_setups);
-       snd_array_free(&codec->spdif_out);
-       snd_array_free(&codec->verbs);
-       codec->num_pcms = 0;
-       codec->pcm_info = NULL;
-       codec->preset = NULL;
-       codec->slave_dig_outs = NULL;
-       codec->spdif_status_reset = 0;
-       unload_parser(codec);
-       module_put(codec->owner);
-       codec->owner = NULL;
+       if (device_is_registered(hda_codec_dev(codec)))
+               device_del(hda_codec_dev(codec));
 
        /* allow device access again */
        snd_hda_unlock_devices(bus);
@@ -3153,19 +2836,19 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
        long *valp = ucontrol->value.integer.value;
        int change = 0;
 
-       snd_hda_power_up(codec);
        if (chs & 1) {
-               change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
-                                                 HDA_AMP_MUTE,
-                                                 *valp ? 0 : HDA_AMP_MUTE);
+               change = codec_amp_update(codec, nid, 0, dir, idx,
+                                         HDA_AMP_MUTE,
+                                         *valp ? 0 : HDA_AMP_MUTE, false,
+                                         !hda_codec_is_power_on(codec));
                valp++;
        }
        if (chs & 2)
-               change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
-                                                  HDA_AMP_MUTE,
-                                                  *valp ? 0 : HDA_AMP_MUTE);
+               change |= codec_amp_update(codec, nid, 1, dir, idx,
+                                          HDA_AMP_MUTE,
+                                          *valp ? 0 : HDA_AMP_MUTE, false,
+                                          !hda_codec_is_power_on(codec));
        hda_call_check_power_status(codec, nid);
-       snd_hda_power_down(codec);
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put);
@@ -4212,31 +3895,40 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
 #endif
 
 #ifdef CONFIG_PM
+/* update the power on/off account with the current jiffies */
+static void update_power_acct(struct hda_codec *codec, bool on)
+{
+       unsigned long delta = jiffies - codec->power_jiffies;
+
+       if (on)
+               codec->power_on_acct += delta;
+       else
+               codec->power_off_acct += delta;
+       codec->power_jiffies += delta;
+}
+
+void snd_hda_update_power_acct(struct hda_codec *codec)
+{
+       update_power_acct(codec, hda_codec_is_power_on(codec));
+}
+
 /*
  * call suspend and power-down; used both from PM and power-save
  * this function returns the power state in the end
  */
-static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
+static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
 {
        unsigned int state;
 
-       codec->in_pm = 1;
+       atomic_inc(&codec->in_pm);
 
        if (codec->patch_ops.suspend)
                codec->patch_ops.suspend(codec);
        hda_cleanup_all_streams(codec);
        state = hda_set_power_state(codec, AC_PWRST_D3);
-       /* Cancel delayed work if we aren't currently running from it. */
-       if (!in_wq)
-               cancel_delayed_work_sync(&codec->power_work);
-       spin_lock(&codec->power_lock);
-       snd_hda_update_power_acct(codec);
        trace_hda_power_down(codec);
-       codec->power_on = 0;
-       codec->power_transition = 0;
-       codec->power_jiffies = jiffies;
-       spin_unlock(&codec->power_lock);
-       codec->in_pm = 0;
+       update_power_acct(codec, true);
+       atomic_dec(&codec->in_pm);
        return state;
 }
 
@@ -4261,14 +3953,13 @@ static void hda_mark_cmd_cache_dirty(struct hda_codec *codec)
  */
 static void hda_call_codec_resume(struct hda_codec *codec)
 {
-       codec->in_pm = 1;
+       atomic_inc(&codec->in_pm);
 
+       trace_hda_power_up(codec);
        hda_mark_cmd_cache_dirty(codec);
 
-       /* set as if powered on for avoiding re-entering the resume
-        * in the resume / power-save sequence
-        */
-       hda_keep_power_on(codec);
+       codec->power_jiffies = jiffies;
+
        hda_set_power_state(codec, AC_PWRST_D0);
        restore_shutup_pins(codec);
        hda_exec_init_verbs(codec);
@@ -4286,64 +3977,63 @@ static void hda_call_codec_resume(struct hda_codec *codec)
                hda_jackpoll_work(&codec->jackpoll_work.work);
        else
                snd_hda_jack_report_sync(codec);
-
-       codec->in_pm = 0;
-       snd_hda_power_down(codec); /* flag down before returning */
+       atomic_dec(&codec->in_pm);
 }
-#endif /* CONFIG_PM */
 
+static int hda_codec_runtime_suspend(struct device *dev)
+{
+       struct hda_codec *codec = dev_to_hda_codec(dev);
+       struct hda_pcm *pcm;
+       unsigned int state;
 
-/**
- * snd_hda_build_controls - build mixer controls
- * @bus: the BUS
- *
- * Creates mixer controls for each codec included in the bus.
- *
- * Returns 0 if successful, otherwise a negative error code.
- */
-int snd_hda_build_controls(struct hda_bus *bus)
+       cancel_delayed_work_sync(&codec->jackpoll_work);
+       list_for_each_entry(pcm, &codec->pcm_list_head, list)
+               snd_pcm_suspend_all(pcm->pcm);
+       state = hda_call_codec_suspend(codec);
+       if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK))
+               clear_bit(codec->addr, &codec->bus->codec_powered);
+       return 0;
+}
+
+static int hda_codec_runtime_resume(struct device *dev)
 {
-       struct hda_codec *codec;
+       struct hda_codec *codec = dev_to_hda_codec(dev);
 
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               int err = snd_hda_codec_build_controls(codec);
-               if (err < 0) {
-                       codec_err(codec,
-                                 "cannot build controls for #%d (error %d)\n",
-                                 codec->addr, err);
-                       err = snd_hda_codec_reset(codec);
-                       if (err < 0) {
-                               codec_err(codec,
-                                         "cannot revert codec\n");
-                               return err;
-                       }
-               }
-       }
+       set_bit(codec->addr, &codec->bus->codec_powered);
+       hda_call_codec_resume(codec);
+       pm_runtime_mark_last_busy(dev);
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_hda_build_controls);
+#endif /* CONFIG_PM */
+
+/* referred in hda_bind.c */
+const struct dev_pm_ops hda_codec_driver_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume,
+                          NULL)
+};
 
 /*
  * add standard channel maps if not specified
  */
 static int add_std_chmaps(struct hda_codec *codec)
 {
-       int i, str, err;
+       struct hda_pcm *pcm;
+       int str, err;
 
-       for (i = 0; i < codec->num_pcms; i++) {
+       list_for_each_entry(pcm, &codec->pcm_list_head, list) {
                for (str = 0; str < 2; str++) {
-                       struct snd_pcm *pcm = codec->pcm_info[i].pcm;
-                       struct hda_pcm_stream *hinfo =
-                               &codec->pcm_info[i].stream[str];
+                       struct hda_pcm_stream *hinfo = &pcm->stream[str];
                        struct snd_pcm_chmap *chmap;
                        const struct snd_pcm_chmap_elem *elem;
 
-                       if (codec->pcm_info[i].own_chmap)
+                       if (pcm->own_chmap)
                                continue;
                        if (!pcm || !hinfo->substreams)
                                continue;
                        elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps;
-                       err = snd_pcm_add_chmap_ctls(pcm, str, elem,
+                       err = snd_pcm_add_chmap_ctls(pcm->pcm, str, elem,
                                                     hinfo->channels_max,
                                                     0, &chmap);
                        if (err < 0)
@@ -4792,7 +4482,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
 {
        int ret;
        mutex_lock(&codec->bus->prepare_mutex);
-       ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream);
+       if (hinfo->ops.prepare)
+               ret = hinfo->ops.prepare(hinfo, codec, stream, format,
+                                        substream);
+       else
+               ret = -ENODEV;
        if (ret >= 0)
                purify_inactive_streams(codec);
        mutex_unlock(&codec->bus->prepare_mutex);
@@ -4813,7 +4507,8 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,
                           struct snd_pcm_substream *substream)
 {
        mutex_lock(&codec->bus->prepare_mutex);
-       hinfo->ops.cleanup(hinfo, codec, substream);
+       if (hinfo->ops.cleanup)
+               hinfo->ops.cleanup(hinfo, codec, substream);
        mutex_unlock(&codec->bus->prepare_mutex);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup);
@@ -4871,112 +4566,84 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
        return -EAGAIN;
 }
 
-/*
- * attach a new PCM stream
- */
-static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
+/* call build_pcms ops of the given codec and set up the default parameters */
+int snd_hda_codec_parse_pcms(struct hda_codec *codec)
 {
-       struct hda_bus *bus = codec->bus;
-       struct hda_pcm_stream *info;
-       int stream, err;
+       struct hda_pcm *cpcm;
+       int err;
 
-       if (snd_BUG_ON(!pcm->name))
-               return -EINVAL;
-       for (stream = 0; stream < 2; stream++) {
-               info = &pcm->stream[stream];
-               if (info->substreams) {
+       if (!list_empty(&codec->pcm_list_head))
+               return 0; /* already parsed */
+
+       if (!codec->patch_ops.build_pcms)
+               return 0;
+
+       err = codec->patch_ops.build_pcms(codec);
+       if (err < 0) {
+               codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
+                         codec->addr, err);
+               return err;
+       }
+
+       list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
+               int stream;
+
+               for (stream = 0; stream < 2; stream++) {
+                       struct hda_pcm_stream *info = &cpcm->stream[stream];
+
+                       if (!info->substreams)
+                               continue;
                        err = set_pcm_default_values(codec, info);
-                       if (err < 0)
+                       if (err < 0) {
+                               codec_warn(codec,
+                                          "fail to setup default for PCM %s\n",
+                                          cpcm->name);
                                return err;
+                       }
                }
        }
-       return bus->ops.attach_pcm(bus, codec, pcm);
+
+       return 0;
 }
 
 /* assign all PCMs of the given codec */
 int snd_hda_codec_build_pcms(struct hda_codec *codec)
 {
-       unsigned int pcm;
-       int err;
+       struct hda_bus *bus = codec->bus;
+       struct hda_pcm *cpcm;
+       int dev, err;
 
-       if (!codec->num_pcms) {
-               if (!codec->patch_ops.build_pcms)
-                       return 0;
-               err = codec->patch_ops.build_pcms(codec);
-               if (err < 0) {
-                       codec_err(codec,
-                                 "cannot build PCMs for #%d (error %d)\n",
-                                 codec->addr, err);
-                       err = snd_hda_codec_reset(codec);
-                       if (err < 0) {
-                               codec_err(codec,
-                                         "cannot revert codec\n");
-                               return err;
-                       }
-               }
+       if (snd_BUG_ON(!bus->ops.attach_pcm))
+               return -EINVAL;
+
+       err = snd_hda_codec_parse_pcms(codec);
+       if (err < 0) {
+               snd_hda_codec_reset(codec);
+               return err;
        }
-       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-               struct hda_pcm *cpcm = &codec->pcm_info[pcm];
-               int dev;
 
+       /* attach a new PCM streams */
+       list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
+               if (cpcm->pcm)
+                       continue; /* already attached */
                if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
                        continue; /* no substreams assigned */
 
-               if (!cpcm->pcm) {
-                       dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
-                       if (dev < 0)
-                               continue; /* no fatal error */
-                       cpcm->device = dev;
-                       err = snd_hda_attach_pcm(codec, cpcm);
-                       if (err < 0) {
-                               codec_err(codec,
-                                         "cannot attach PCM stream %d for codec #%d\n",
-                                         dev, codec->addr);
-                               continue; /* no fatal error */
-                       }
+               dev = get_empty_pcm_device(bus, cpcm->pcm_type);
+               if (dev < 0)
+                       continue; /* no fatal error */
+               cpcm->device = dev;
+               err =  bus->ops.attach_pcm(bus, codec, cpcm);
+               if (err < 0) {
+                       codec_err(codec,
+                                 "cannot attach PCM stream %d for codec #%d\n",
+                                 dev, codec->addr);
+                       continue; /* no fatal error */
                }
        }
-       return 0;
-}
 
-/**
- * snd_hda_build_pcms - build PCM information
- * @bus: the BUS
- *
- * Create PCM information for each codec included in the bus.
- *
- * The build_pcms codec patch is requested to set up codec->num_pcms and
- * codec->pcm_info properly.  The array is referred by the top-level driver
- * to create its PCM instances.
- * The allocated codec->pcm_info should be released in codec->patch_ops.free
- * callback.
- *
- * At least, substreams, channels_min and channels_max must be filled for
- * each stream.  substreams = 0 indicates that the stream doesn't exist.
- * When rates and/or formats are zero, the supported values are queried
- * from the given nid.  The nid is used also by the default ops.prepare
- * and ops.cleanup callbacks.
- *
- * The driver needs to call ops.open in its open callback.  Similarly,
- * ops.close is supposed to be called in the close callback.
- * ops.prepare should be called in the prepare or hw_params callback
- * with the proper parameters for set up.
- * ops.cleanup should be called in hw_free for clean up of streams.
- *
- * This function returns 0 if successful, or a negative error code.
- */
-int snd_hda_build_pcms(struct hda_bus *bus)
-{
-       struct hda_codec *codec;
-
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               int err = snd_hda_codec_build_pcms(codec);
-               if (err < 0)
-                       return err;
-       }
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
 
 /**
  * snd_hda_add_new_ctls - create controls from the array
@@ -5029,127 +4696,70 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
 EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
 
 #ifdef CONFIG_PM
-static void hda_power_work(struct work_struct *work)
+/**
+ * snd_hda_power_up - Power-up the codec
+ * @codec: HD-audio codec
+ *
+ * Increment the usage counter and resume the device if not done yet.
+ */
+void snd_hda_power_up(struct hda_codec *codec)
 {
-       struct hda_codec *codec =
-               container_of(work, struct hda_codec, power_work.work);
-       struct hda_bus *bus = codec->bus;
-       unsigned int state;
+       struct device *dev = hda_codec_dev(codec);
 
-       spin_lock(&codec->power_lock);
-       if (codec->power_transition > 0) { /* during power-up sequence? */
-               spin_unlock(&codec->power_lock);
-               return;
-       }
-       if (!codec->power_on || codec->power_count) {
-               codec->power_transition = 0;
-               spin_unlock(&codec->power_lock);
+       if (codec_in_pm(codec))
                return;
-       }
-       spin_unlock(&codec->power_lock);
-
-       state = hda_call_codec_suspend(codec, true);
-       if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK))
-               hda_call_pm_notify(codec, false);
+       pm_runtime_get_sync(dev);
 }
+EXPORT_SYMBOL_GPL(snd_hda_power_up);
 
-static void hda_keep_power_on(struct hda_codec *codec)
-{
-       spin_lock(&codec->power_lock);
-       codec->power_count++;
-       codec->power_on = 1;
-       codec->power_jiffies = jiffies;
-       spin_unlock(&codec->power_lock);
-       hda_call_pm_notify(codec, true);
-}
-
-/* update the power on/off account with the current jiffies */
-void snd_hda_update_power_acct(struct hda_codec *codec)
-{
-       unsigned long delta = jiffies - codec->power_jiffies;
-       if (codec->power_on)
-               codec->power_on_acct += delta;
-       else
-               codec->power_off_acct += delta;
-       codec->power_jiffies += delta;
-}
-
-/* Transition to powered up, if wait_power_down then wait for a pending
- * transition to D3 to complete. A pending D3 transition is indicated
- * with power_transition == -1. */
-/* call this with codec->power_lock held! */
-static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
+/**
+ * snd_hda_power_down - Power-down the codec
+ * @codec: HD-audio codec
+ *
+ * Decrement the usage counter and schedules the autosuspend if none used.
+ */
+void snd_hda_power_down(struct hda_codec *codec)
 {
-       /* Return if power_on or transitioning to power_on, unless currently
-        * powering down. */
-       if ((codec->power_on || codec->power_transition > 0) &&
-           !(wait_power_down && codec->power_transition < 0))
-               return;
-       spin_unlock(&codec->power_lock);
-
-       cancel_delayed_work_sync(&codec->power_work);
+       struct device *dev = hda_codec_dev(codec);
 
-       spin_lock(&codec->power_lock);
-       /* If the power down delayed work was cancelled above before starting,
-        * then there is no need to go through power up here.
-        */
-       if (codec->power_on) {
-               if (codec->power_transition < 0)
-                       codec->power_transition = 0;
+       if (codec_in_pm(codec))
                return;
-       }
-
-       trace_hda_power_up(codec);
-       snd_hda_update_power_acct(codec);
-       codec->power_on = 1;
-       codec->power_jiffies = jiffies;
-       codec->power_transition = 1; /* avoid reentrance */
-       spin_unlock(&codec->power_lock);
-
-       hda_call_codec_resume(codec);
-
-       spin_lock(&codec->power_lock);
-       codec->power_transition = 0;
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
 }
+EXPORT_SYMBOL_GPL(snd_hda_power_down);
 
-#define power_save(codec)      \
-       ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
-
-/* Transition to powered down */
-static void __snd_hda_power_down(struct hda_codec *codec)
+static void codec_set_power_save(struct hda_codec *codec, int delay)
 {
-       if (!codec->power_on || codec->power_count || codec->power_transition)
-               return;
+       struct device *dev = hda_codec_dev(codec);
 
-       if (power_save(codec)) {
-               codec->power_transition = -1; /* avoid reentrance */
-               queue_delayed_work(codec->bus->workq, &codec->power_work,
-                               msecs_to_jiffies(power_save(codec) * 1000));
+       if (delay > 0) {
+               pm_runtime_set_autosuspend_delay(dev, delay);
+               pm_runtime_use_autosuspend(dev);
+               pm_runtime_allow(dev);
+               if (!pm_runtime_suspended(dev))
+                       pm_runtime_mark_last_busy(dev);
+       } else {
+               pm_runtime_dont_use_autosuspend(dev);
+               pm_runtime_forbid(dev);
        }
 }
 
 /**
- * snd_hda_power_save - Power-up/down/sync the codec
- * @codec: HD-audio codec
- * @delta: the counter delta to change
- * @d3wait: sync for D3 transition complete
+ * snd_hda_set_power_save - reprogram autosuspend for the given delay
+ * @bus: HD-audio bus
+ * @delay: autosuspend delay in msec, 0 = off
  *
- * Change the power-up counter via @delta, and power up or down the hardware
- * appropriately.  For the power-down, queue to the delayed action.
- * Passing zero to @delta means to synchronize the power state.
+ * Synchronize the runtime PM autosuspend state from the power_save option.
  */
-void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
+void snd_hda_set_power_save(struct hda_bus *bus, int delay)
 {
-       spin_lock(&codec->power_lock);
-       codec->power_count += delta;
-       trace_hda_power_count(codec);
-       if (delta > 0)
-               __snd_hda_power_up(codec, d3wait);
-       else
-               __snd_hda_power_down(codec);
-       spin_unlock(&codec->power_lock);
+       struct hda_codec *c;
+
+       list_for_each_entry(c, &bus->codec_list, list)
+               codec_set_power_save(c, delay);
 }
-EXPORT_SYMBOL_GPL(snd_hda_power_save);
+EXPORT_SYMBOL_GPL(snd_hda_set_power_save);
 
 /**
  * snd_hda_check_amp_list_power - Check the amp list and update the power
@@ -5202,88 +4812,6 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
 #endif
 
-/*
- * Channel mode helper
- */
-
-/**
- * snd_hda_ch_mode_info - Info callback helper for the channel mode enum
- * @codec: the HDA codec
- * @uinfo: pointer to get/store the data
- * @chmode: channel mode array
- * @num_chmodes: channel mode array size
- */
-int snd_hda_ch_mode_info(struct hda_codec *codec,
-                        struct snd_ctl_elem_info *uinfo,
-                        const struct hda_channel_mode *chmode,
-                        int num_chmodes)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = num_chmodes;
-       if (uinfo->value.enumerated.item >= num_chmodes)
-               uinfo->value.enumerated.item = num_chmodes - 1;
-       sprintf(uinfo->value.enumerated.name, "%dch",
-               chmode[uinfo->value.enumerated.item].channels);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info);
-
-/**
- * snd_hda_ch_mode_get - Get callback helper for the channel mode enum
- * @codec: the HDA codec
- * @ucontrol: pointer to get/store the data
- * @chmode: channel mode array
- * @num_chmodes: channel mode array size
- * @max_channels: max number of channels
- */
-int snd_hda_ch_mode_get(struct hda_codec *codec,
-                       struct snd_ctl_elem_value *ucontrol,
-                       const struct hda_channel_mode *chmode,
-                       int num_chmodes,
-                       int max_channels)
-{
-       int i;
-
-       for (i = 0; i < num_chmodes; i++) {
-               if (max_channels == chmode[i].channels) {
-                       ucontrol->value.enumerated.item[0] = i;
-                       break;
-               }
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get);
-
-/**
- * snd_hda_ch_mode_put - Put callback helper for the channel mode enum
- * @codec: the HDA codec
- * @ucontrol: pointer to get/store the data
- * @chmode: channel mode array
- * @num_chmodes: channel mode array size
- * @max_channelsp: pointer to store the max channels
- */
-int snd_hda_ch_mode_put(struct hda_codec *codec,
-                       struct snd_ctl_elem_value *ucontrol,
-                       const struct hda_channel_mode *chmode,
-                       int num_chmodes,
-                       int *max_channelsp)
-{
-       unsigned int mode;
-
-       mode = ucontrol->value.enumerated.item[0];
-       if (mode >= num_chmodes)
-               return -EINVAL;
-       if (*max_channelsp == chmode[mode].channels)
-               return 0;
-       /* change the current channel setting */
-       *max_channelsp = chmode[mode].channels;
-       if (chmode[mode].sequence)
-               snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
-       return 1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put);
-
 /*
  * input MUX helper
  */
@@ -5417,24 +4945,6 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
        }
 }
 
-/**
- * snd_hda_bus_reboot_notify - call the reboot notifier of each codec
- * @bus: HD-audio bus
- */
-void snd_hda_bus_reboot_notify(struct hda_bus *bus)
-{
-       struct hda_codec *codec;
-
-       if (!bus)
-               return;
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               if (hda_codec_is_power_on(codec) &&
-                   codec->patch_ops.reboot_notify)
-                       codec->patch_ops.reboot_notify(codec);
-       }
-}
-EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify);
-
 /**
  * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
  * @codec: the HDA codec
@@ -5825,77 +5335,26 @@ int snd_hda_add_imux_item(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_hda_add_imux_item);
 
-
-#ifdef CONFIG_PM
-/*
- * power management
- */
-
-
-static void hda_async_suspend(void *data, async_cookie_t cookie)
-{
-       hda_call_codec_suspend(data, false);
-}
-
-static void hda_async_resume(void *data, async_cookie_t cookie)
-{
-       hda_call_codec_resume(data);
-}
-
 /**
- * snd_hda_suspend - suspend the codecs
- * @bus: the HDA bus
- *
- * Returns 0 if successful.
+ * snd_hda_bus_reset - Reset the bus
+ * @bus: HD-audio bus
  */
-int snd_hda_suspend(struct hda_bus *bus)
+void snd_hda_bus_reset(struct hda_bus *bus)
 {
        struct hda_codec *codec;
-       ASYNC_DOMAIN_EXCLUSIVE(domain);
 
        list_for_each_entry(codec, &bus->codec_list, list) {
+               /* FIXME: maybe a better way needed for forced reset */
                cancel_delayed_work_sync(&codec->jackpoll_work);
+#ifdef CONFIG_PM
                if (hda_codec_is_power_on(codec)) {
-                       if (bus->num_codecs > 1)
-                               async_schedule_domain(hda_async_suspend, codec,
-                                                     &domain);
-                       else
-                               hda_call_codec_suspend(codec, false);
-               }
-       }
-
-       if (bus->num_codecs > 1)
-               async_synchronize_full_domain(&domain);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_suspend);
-
-/**
- * snd_hda_resume - resume the codecs
- * @bus: the HDA bus
- *
- * Returns 0 if successful.
- */
-int snd_hda_resume(struct hda_bus *bus)
-{
-       struct hda_codec *codec;
-       ASYNC_DOMAIN_EXCLUSIVE(domain);
-
-       list_for_each_entry(codec, &bus->codec_list, list) {
-               if (bus->num_codecs > 1)
-                       async_schedule_domain(hda_async_resume, codec, &domain);
-               else
+                       hda_call_codec_suspend(codec);
                        hda_call_codec_resume(codec);
+               }
+#endif
        }
-
-       if (bus->num_codecs > 1)
-               async_synchronize_full_domain(&domain);
-
-       return 0;
 }
-EXPORT_SYMBOL_GPL(snd_hda_resume);
-#endif /* CONFIG_PM */
+EXPORT_SYMBOL_GPL(snd_hda_bus_reset);
 
 /*
  * generic arrays
index 9c8820f21f948ffb98bea96a0804d6e9b80e1aa8..ccf355d4a8fa0909a33922a2db3ae080de3437d7 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef __SOUND_HDA_CODEC_H
 #define __SOUND_HDA_CODEC_H
 
+#include <linux/kref.h>
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -66,7 +67,6 @@ struct hda_beep;
 struct hda_codec;
 struct hda_pcm;
 struct hda_pcm_stream;
-struct hda_bus_unsolicited;
 
 /* NID type */
 typedef u16 hda_nid_t;
@@ -84,10 +84,6 @@ struct hda_bus_ops {
                          struct hda_pcm *pcm);
        /* reset bus for retry verb */
        void (*bus_reset)(struct hda_bus *bus);
-#ifdef CONFIG_PM
-       /* 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,
@@ -101,13 +97,14 @@ struct hda_bus_ops {
 #endif
 };
 
-/* template to pass to the bus constructor */
-struct hda_bus_template {
-       void *private_data;
-       struct pci_dev *pci;
-       const char *modelname;
-       int *power_save;
-       struct hda_bus_ops ops;
+/* unsolicited event handler */
+#define HDA_UNSOL_QUEUE_SIZE   64
+struct hda_bus_unsolicited {
+       /* ring buffer */
+       u32 queue[HDA_UNSOL_QUEUE_SIZE * 2];
+       unsigned int rp, wp;
+       /* workqueue */
+       struct work_struct work;
 };
 
 /*
@@ -119,11 +116,9 @@ struct hda_bus_template {
 struct hda_bus {
        struct snd_card *card;
 
-       /* copied from template */
        void *private_data;
        struct pci_dev *pci;
        const char *modelname;
-       int *power_save;
        struct hda_bus_ops ops;
 
        /* codec linked list */
@@ -136,9 +131,7 @@ struct hda_bus {
        struct mutex prepare_mutex;
 
        /* unsolicited event queue */
-       struct hda_bus_unsolicited *unsol;
-       char workq_name[16];
-       struct workqueue_struct *workq; /* common workqueue for codecs */
+       struct hda_bus_unsolicited unsol;
 
        /* assigned PCMs */
        DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
@@ -152,10 +145,10 @@ struct hda_bus {
        unsigned int rirb_error:1;      /* error in codec communication */
        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 */
        unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
 
        int primary_dig_out_type;       /* primary digital out PCM type */
+       unsigned long codec_powered;    /* bit flags of powered codecs */
 };
 
 /*
@@ -175,15 +168,22 @@ struct hda_codec_preset {
        int (*patch)(struct hda_codec *codec);
 };
        
-struct hda_codec_preset_list {
+#define HDA_CODEC_ID_GENERIC_HDMI      0x00000101
+#define HDA_CODEC_ID_GENERIC           0x00000201
+
+struct hda_codec_driver {
+       struct device_driver driver;
        const struct hda_codec_preset *preset;
-       struct module *owner;
-       struct list_head list;
 };
 
-/* initial hook */
-int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset);
-int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset);
+int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
+                              struct module *owner);
+#define hda_codec_driver_register(drv) \
+       __hda_codec_driver_register(drv, KBUILD_MODNAME, THIS_MODULE)
+void hda_codec_driver_unregister(struct hda_codec_driver *drv);
+#define module_hda_codec_driver(drv) \
+       module_driver(drv, hda_codec_driver_register, \
+                     hda_codec_driver_unregister)
 
 /* ops set by the preset patch */
 struct hda_codec_ops {
@@ -200,6 +200,7 @@ struct hda_codec_ops {
        int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
 #endif
        void (*reboot_notify)(struct hda_codec *codec);
+       void (*stream_pm)(struct hda_codec *codec, hda_nid_t nid, bool on);
 };
 
 /* record for amp information cache */
@@ -267,12 +268,17 @@ struct hda_pcm {
        int device;             /* device number to assign */
        struct snd_pcm *pcm;    /* assigned PCM instance */
        bool own_chmap;         /* codec driver provides own channel maps */
+       /* private: */
+       struct hda_codec *codec;
+       struct kref kref;
+       struct list_head list;
 };
 
 /* codec information */
 struct hda_codec {
        struct device dev;
        struct hda_bus *bus;
+       struct snd_card *card;
        unsigned int addr;      /* codec addr*/
        struct list_head list;  /* list point */
 
@@ -287,11 +293,10 @@ struct hda_codec {
        u32 vendor_id;
        u32 subsystem_id;
        u32 revision_id;
+       u32 probe_id; /* overridden id for probing */
 
        /* detected preset */
        const struct hda_codec_preset *preset;
-       struct module *owner;
-       int (*parser)(struct hda_codec *codec);
        const char *vendor_name;        /* codec vendor name */
        const char *chip_name;          /* codec chip name */
        const char *modelname;  /* model name for preset */
@@ -300,8 +305,7 @@ struct hda_codec {
        struct hda_codec_ops patch_ops;
 
        /* PCM to create, set by patch_ops.build_pcms callback */
-       unsigned int num_pcms;
-       struct hda_pcm *pcm_info;
+       struct list_head pcm_list_head;
 
        /* codec specific info */
        void *spec;
@@ -345,6 +349,7 @@ struct hda_codec {
 #endif
 
        /* misc flags */
+       unsigned int in_freeing:1; /* being released */
        unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
                                             * status change
                                             * (e.g. Realtek codecs)
@@ -366,18 +371,13 @@ struct hda_codec {
        unsigned int cached_write:1;    /* write only to caches */
        unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
        unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
+       unsigned int power_save_node:1; /* advanced PM for each widget */
 #ifdef CONFIG_PM
-       unsigned int power_on :1;       /* current (global) power-state */
        unsigned int d3_stop_clk:1;     /* support D3 operation without BCLK */
-       unsigned int pm_up_notified:1;  /* PM notified to controller */
-       unsigned int in_pm:1;           /* suspend/resume being performed */
-       int power_transition;   /* power-state in transition */
-       int power_count;        /* current (global) power refcount */
-       struct delayed_work power_work; /* delayed task for powerdown */
+       atomic_t in_pm;         /* suspend/resume being performed */
        unsigned long power_on_acct;
        unsigned long power_off_acct;
        unsigned long power_jiffies;
-       spinlock_t power_lock;
 #endif
 
        /* filter the requested power state per nid */
@@ -409,6 +409,11 @@ struct hda_codec {
        struct snd_array verbs;
 };
 
+#define dev_to_hda_codec(_dev) container_of(_dev, struct hda_codec, dev)
+#define hda_codec_dev(_dev)    (&(_dev)->dev)
+
+extern struct bus_type snd_hda_bus_type;
+
 /* direction */
 enum {
        HDA_INPUT, HDA_OUTPUT
@@ -420,10 +425,9 @@ enum {
 /*
  * constructors
  */
-int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp,
-                   struct hda_bus **busp);
-int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
-                     struct hda_codec **codecp);
+int snd_hda_bus_new(struct snd_card *card, struct hda_bus **busp);
+int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
+                     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);
 
@@ -512,15 +516,24 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid);
 /*
  * Mixer
  */
-int snd_hda_build_controls(struct hda_bus *bus);
 int snd_hda_codec_build_controls(struct hda_codec *codec);
 
 /*
  * PCM
  */
-int snd_hda_build_pcms(struct hda_bus *bus);
+int snd_hda_codec_parse_pcms(struct hda_codec *codec);
 int snd_hda_codec_build_pcms(struct hda_codec *codec);
 
+__printf(2, 3)
+struct hda_pcm *snd_hda_codec_pcm_new(struct hda_codec *codec,
+                                     const char *fmt, ...);
+
+static inline void snd_hda_codec_pcm_get(struct hda_pcm *pcm)
+{
+       kref_get(&pcm->kref);
+}
+void snd_hda_codec_pcm_put(struct hda_pcm *pcm);
+
 int snd_hda_codec_prepare(struct hda_codec *codec,
                          struct hda_pcm_stream *hinfo,
                          unsigned int stream,
@@ -552,20 +565,17 @@ extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[];
  * Misc
  */
 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);
 
 int snd_hda_lock_devices(struct hda_bus *bus);
 void snd_hda_unlock_devices(struct hda_bus *bus);
+void snd_hda_bus_reset(struct hda_bus *bus);
 
 /*
  * power management
  */
-#ifdef CONFIG_PM
-int snd_hda_suspend(struct hda_bus *bus);
-int snd_hda_resume(struct hda_bus *bus);
-#endif
+extern const struct dev_pm_ops hda_codec_driver_pm;
 
 static inline
 int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
@@ -588,64 +598,16 @@ const char *snd_hda_get_jack_location(u32 cfg);
  * power saving
  */
 #ifdef CONFIG_PM
-void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);
+void snd_hda_power_up(struct hda_codec *codec);
+void snd_hda_power_down(struct hda_codec *codec);
+void snd_hda_set_power_save(struct hda_bus *bus, int delay);
 void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
-static inline void snd_hda_power_save(struct hda_codec *codec, int delta,
-                                     bool d3wait) {}
+static inline void snd_hda_power_up(struct hda_codec *codec) {}
+static inline void snd_hda_power_down(struct hda_codec *codec) {}
+static inline void snd_hda_set_power_save(struct hda_bus *bus, int delay) {}
 #endif
 
-/**
- * snd_hda_power_up - Power-up the codec
- * @codec: HD-audio codec
- *
- * Increment the power-up counter and power up the hardware really when
- * not turned on yet.
- */
-static inline void snd_hda_power_up(struct hda_codec *codec)
-{
-       snd_hda_power_save(codec, 1, false);
-}
-
-/**
- * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
- *   D3 transition to complete.  This differs from snd_hda_power_up() when
- *   power_transition == -1.  snd_hda_power_up sees this case as a nop,
- *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
- *   back up.
- * @codec: HD-audio codec
- *
- * Cancel any power down operation hapenning on the work queue, then power up.
- */
-static inline void snd_hda_power_up_d3wait(struct hda_codec *codec)
-{
-       snd_hda_power_save(codec, 1, true);
-}
-
-/**
- * snd_hda_power_down - Power-down the codec
- * @codec: HD-audio codec
- *
- * Decrement the power-up counter and schedules the power-off work if
- * the counter rearches to zero.
- */
-static inline void snd_hda_power_down(struct hda_codec *codec)
-{
-       snd_hda_power_save(codec, -1, false);
-}
-
-/**
- * snd_hda_power_sync - Synchronize the power-save status
- * @codec: HD-audio codec
- *
- * Synchronize the actual power state with the power account;
- * called when power_save parameter is changed
- */
-static inline void snd_hda_power_sync(struct hda_codec *codec)
-{
-       snd_hda_power_save(codec, 0, false);
-}
-
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 /*
  * patch firmware
index 17c2637d842c1c366275683f30d2a3cb743560b6..4fd0b2ef26e9f469ce964d954b6170b638266402 100644 (file)
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
-#include <linux/reboot.h>
 #include <sound/core.h>
 #include <sound/initval.h>
-#include "hda_priv.h"
 #include "hda_controller.h"
 
 #define CREATE_TRACE_POINTS
@@ -259,11 +257,18 @@ static void azx_timecounter_init(struct snd_pcm_substream *substream,
                tc->cycle_last = last;
 }
 
+static inline struct hda_pcm_stream *
+to_hda_pcm_stream(struct snd_pcm_substream *substream)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       return &apcm->info->stream[substream->stream];
+}
+
 static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
                                u64 nsec)
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
        u64 codec_frames, codec_nsecs;
 
        if (!hinfo->ops.get_delay)
@@ -399,7 +404,7 @@ static int azx_setup_periods(struct azx *chip,
 static int azx_pcm_close(struct snd_pcm_substream *substream)
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
        struct azx *chip = apcm->chip;
        struct azx_dev *azx_dev = get_azx_dev(substream);
        unsigned long flags;
@@ -410,9 +415,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
        azx_dev->running = 0;
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        azx_release_device(azx_dev);
-       hinfo->ops.close(hinfo, apcm->codec, substream);
+       if (hinfo->ops.close)
+               hinfo->ops.close(hinfo, apcm->codec, substream);
        snd_hda_power_down(apcm->codec);
        mutex_unlock(&chip->open_mutex);
+       snd_hda_codec_pcm_put(apcm->info);
        return 0;
 }
 
@@ -441,7 +448,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx_dev *azx_dev = get_azx_dev(substream);
        struct azx *chip = apcm->chip;
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
        int err;
 
        /* reset BDL address */
@@ -468,7 +475,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx *chip = apcm->chip;
        struct azx_dev *azx_dev = get_azx_dev(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        unsigned int bufsize, period_bytes, format_val, stream_tag;
        int err;
@@ -708,7 +715,7 @@ unsigned int azx_get_position(struct azx *chip,
 
        if (substream->runtime) {
                struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-               struct hda_pcm_stream *hinfo = apcm->hinfo[stream];
+               struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 
                if (chip->get_delay[stream])
                        delay += chip->get_delay[stream](chip, azx_dev, pos);
@@ -732,17 +739,32 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
                               azx_get_position(chip, azx_dev));
 }
 
-static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream,
-                               struct timespec *ts)
+static int azx_get_time_info(struct snd_pcm_substream *substream,
+                       struct timespec *system_ts, struct timespec *audio_ts,
+                       struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
+                       struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
 {
        struct azx_dev *azx_dev = get_azx_dev(substream);
        u64 nsec;
 
-       nsec = timecounter_read(&azx_dev->azx_tc);
-       nsec = div_u64(nsec, 3); /* can be optimized */
-       nsec = azx_adjust_codec_delay(substream, nsec);
+       if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) &&
+               (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) {
+
+               snd_pcm_gettime(substream->runtime, system_ts);
 
-       *ts = ns_to_timespec(nsec);
+               nsec = timecounter_read(&azx_dev->azx_tc);
+               nsec = div_u64(nsec, 3); /* can be optimized */
+               if (audio_tstamp_config->report_delay)
+                       nsec = azx_adjust_codec_delay(substream, nsec);
+
+               *audio_ts = ns_to_timespec(nsec);
+
+               audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
+               audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */
+               audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */
+
+       } else
+               audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
 
        return 0;
 }
@@ -756,7 +778,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
                                 /* SNDRV_PCM_INFO_RESUME |*/
                                 SNDRV_PCM_INFO_PAUSE |
                                 SNDRV_PCM_INFO_SYNC_START |
-                                SNDRV_PCM_INFO_HAS_WALL_CLOCK |
+                                SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
+                                SNDRV_PCM_INFO_HAS_LINK_ATIME |
                                 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
@@ -775,7 +798,7 @@ static struct snd_pcm_hardware azx_pcm_hw = {
 static int azx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
+       struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
        struct azx *chip = apcm->chip;
        struct azx_dev *azx_dev;
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -783,11 +806,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        int err;
        int buff_step;
 
+       snd_hda_codec_pcm_get(apcm->info);
        mutex_lock(&chip->open_mutex);
        azx_dev = azx_assign_device(chip, substream);
        if (azx_dev == NULL) {
-               mutex_unlock(&chip->open_mutex);
-               return -EBUSY;
+               err = -EBUSY;
+               goto unlock;
        }
        runtime->hw = azx_pcm_hw;
        runtime->hw.channels_min = hinfo->channels_min;
@@ -821,13 +845,14 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                                   buff_step);
        snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
                                   buff_step);
-       snd_hda_power_up_d3wait(apcm->codec);
-       err = hinfo->ops.open(hinfo, apcm->codec, substream);
+       snd_hda_power_up(apcm->codec);
+       if (hinfo->ops.open)
+               err = hinfo->ops.open(hinfo, apcm->codec, substream);
+       else
+               err = -ENODEV;
        if (err < 0) {
                azx_release_device(azx_dev);
-               snd_hda_power_down(apcm->codec);
-               mutex_unlock(&chip->open_mutex);
-               return err;
+               goto powerdown;
        }
        snd_pcm_limit_hw_rates(runtime);
        /* sanity check */
@@ -836,16 +861,18 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
            snd_BUG_ON(!runtime->hw.formats) ||
            snd_BUG_ON(!runtime->hw.rates)) {
                azx_release_device(azx_dev);
-               hinfo->ops.close(hinfo, apcm->codec, substream);
-               snd_hda_power_down(apcm->codec);
-               mutex_unlock(&chip->open_mutex);
-               return -EINVAL;
+               if (hinfo->ops.close)
+                       hinfo->ops.close(hinfo, apcm->codec, substream);
+               err = -EINVAL;
+               goto powerdown;
        }
 
-       /* disable WALLCLOCK timestamps for capture streams
+       /* disable LINK_ATIME timestamps for capture streams
           until we figure out how to handle digital inputs */
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-               runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK;
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */
+               runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME;
+       }
 
        spin_lock_irqsave(&chip->reg_lock, flags);
        azx_dev->substream = substream;
@@ -856,6 +883,13 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        snd_pcm_set_sync(substream);
        mutex_unlock(&chip->open_mutex);
        return 0;
+
+ powerdown:
+       snd_hda_power_down(apcm->codec);
+ unlock:
+       mutex_unlock(&chip->open_mutex);
+       snd_hda_codec_pcm_put(apcm->info);
+       return err;
 }
 
 static int azx_pcm_mmap(struct snd_pcm_substream *substream,
@@ -877,7 +911,7 @@ static struct snd_pcm_ops azx_pcm_ops = {
        .prepare = azx_pcm_prepare,
        .trigger = azx_pcm_trigger,
        .pointer = azx_pcm_pointer,
-       .wall_clock =  azx_get_wallclock_tstamp,
+       .get_time_info =  azx_get_time_info,
        .mmap = azx_pcm_mmap,
        .page = snd_pcm_sgbuf_ops_page,
 };
@@ -887,6 +921,7 @@ static void azx_pcm_free(struct snd_pcm *pcm)
        struct azx_pcm *apcm = pcm->private_data;
        if (apcm) {
                list_del(&apcm->list);
+               apcm->info->pcm = NULL;
                kfree(apcm);
        }
 }
@@ -923,6 +958,7 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        apcm->chip = chip;
        apcm->pcm = pcm;
        apcm->codec = codec;
+       apcm->info = cpcm;
        pcm->private_data = apcm;
        pcm->private_free = azx_pcm_free;
        if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
@@ -930,7 +966,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        list_add_tail(&apcm->list, &chip->pcm_list);
        cpcm->pcm = pcm;
        for (s = 0; s < 2; s++) {
-               apcm->hinfo[s] = &cpcm->stream[s];
                if (cpcm->stream[s].substreams)
                        snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
        }
@@ -941,9 +976,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                                              chip->card->dev,
                                              size, MAX_PREALLOC_SIZE);
-       /* link to codec */
-       for (s = 0; s < 2; s++)
-               pcm->streams[s].dev.parent = &codec->dev;
        return 0;
 }
 
@@ -952,14 +984,9 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
  */
 static int azx_alloc_cmd_io(struct azx *chip)
 {
-       int err;
-
        /* single page (at least 4096 bytes) must suffice for both ringbuffes */
-       err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
-                                        PAGE_SIZE, &chip->rb);
-       if (err < 0)
-               dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
-       return err;
+       return chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
+                                         PAGE_SIZE, &chip->rb);
 }
 
 static void azx_init_cmd_io(struct azx *chip)
@@ -1445,7 +1472,6 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
 int azx_alloc_stream_pages(struct azx *chip)
 {
        int i, err;
-       struct snd_card *card = chip->card;
 
        for (i = 0; i < chip->num_streams; i++) {
                dsp_lock_init(&chip->azx_dev[i]);
@@ -1453,18 +1479,14 @@ int azx_alloc_stream_pages(struct azx *chip)
                err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
                                                 BDL_SIZE,
                                                 &chip->azx_dev[i].bdl);
-               if (err < 0) {
-                       dev_err(card->dev, "cannot allocate BDL\n");
+               if (err < 0)
                        return -ENOMEM;
-               }
        }
        /* allocate memory for the position buffer */
        err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV,
                                         chip->num_streams * 8, &chip->posbuf);
-       if (err < 0) {
-               dev_err(card->dev, "cannot allocate posbuf\n");
+       if (err < 0)
                return -ENOMEM;
-       }
 
        /* allocate CORB/RIRB */
        err = azx_alloc_cmd_io(chip);
@@ -1676,7 +1698,7 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
        int i;
 
 #ifdef CONFIG_PM
-       if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+       if (azx_has_pm_runtime(chip))
                if (!pm_runtime_active(chip->card->dev))
                        return IRQ_NONE;
 #endif
@@ -1761,34 +1783,11 @@ static void azx_bus_reset(struct hda_bus *bus)
        bus->in_reset = 1;
        azx_stop_chip(chip);
        azx_init_chip(chip, true);
-#ifdef CONFIG_PM
-       if (chip->initialized) {
-               struct azx_pcm *p;
-               list_for_each_entry(p, &chip->pcm_list, list)
-                       snd_pcm_suspend_all(p->pcm);
-               snd_hda_suspend(chip->bus);
-               snd_hda_resume(chip->bus);
-       }
-#endif
+       if (chip->initialized)
+               snd_hda_bus_reset(chip->bus);
        bus->in_reset = 0;
 }
 
-#ifdef CONFIG_PM
-/* power-up/down the controller */
-static void azx_power_notify(struct hda_bus *bus, bool power_up)
-{
-       struct azx *chip = bus->private_data;
-
-       if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
-               return;
-
-       if (power_up)
-               pm_runtime_get_sync(chip->card->dev);
-       else
-               pm_runtime_put_sync(chip->card->dev);
-}
-#endif
-
 static int get_jackpoll_interval(struct azx *chip)
 {
        int i;
@@ -1810,41 +1809,59 @@ static int get_jackpoll_interval(struct azx *chip)
        return j;
 }
 
-/* Codec initialization */
-int azx_codec_create(struct azx *chip, const char *model,
-                    unsigned int max_slots,
-                    int *power_save_to)
-{
-       struct hda_bus_template bus_temp;
-       int c, codecs, err;
-
-       memset(&bus_temp, 0, sizeof(bus_temp));
-       bus_temp.private_data = chip;
-       bus_temp.modelname = model;
-       bus_temp.pci = chip->pci;
-       bus_temp.ops.command = azx_send_cmd;
-       bus_temp.ops.get_response = azx_get_response;
-       bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
-       bus_temp.ops.bus_reset = azx_bus_reset;
-#ifdef CONFIG_PM
-       bus_temp.power_save = power_save_to;
-       bus_temp.ops.pm_notify = azx_power_notify;
-#endif
+static struct hda_bus_ops bus_ops = {
+       .command = azx_send_cmd,
+       .get_response = azx_get_response,
+       .attach_pcm = azx_attach_pcm_stream,
+       .bus_reset = azx_bus_reset,
 #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;
+       .load_dsp_prepare = azx_load_dsp_prepare,
+       .load_dsp_trigger = azx_load_dsp_trigger,
+       .load_dsp_cleanup = azx_load_dsp_cleanup,
 #endif
+};
+
+/* HD-audio bus initialization */
+int azx_bus_create(struct azx *chip, const char *model)
+{
+       struct hda_bus *bus;
+       int err;
 
-       err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus);
+       err = snd_hda_bus_new(chip->card, &bus);
        if (err < 0)
                return err;
 
+       chip->bus = bus;
+       bus->private_data = chip;
+       bus->pci = chip->pci;
+       bus->modelname = model;
+       bus->ops = bus_ops;
+
        if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) {
                dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
-               chip->bus->needs_damn_long_delay = 1;
+               bus->needs_damn_long_delay = 1;
+       }
+
+       /* AMD chipsets often cause the communication stalls upon certain
+        * sequence like the pin-detection.  It seems that forcing the synced
+        * access works around the stall.  Grrr...
+        */
+       if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
+               dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
+               bus->sync_write = 1;
+               bus->allow_bus_reset = 1;
        }
 
+       return 0;
+}
+EXPORT_SYMBOL_GPL(azx_bus_create);
+
+/* Probe codecs */
+int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
+{
+       struct hda_bus *bus = chip->bus;
+       int c, codecs, err;
+
        codecs = 0;
        if (!max_slots)
                max_slots = AZX_DEFAULT_CODECS;
@@ -1872,21 +1889,11 @@ int azx_codec_create(struct azx *chip, const char *model,
                }
        }
 
-       /* AMD chipsets often cause the communication stalls upon certain
-        * sequence like the pin-detection.  It seems that forcing the synced
-        * access works around the stall.  Grrr...
-        */
-       if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) {
-               dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n");
-               chip->bus->sync_write = 1;
-               chip->bus->allow_bus_reset = 1;
-       }
-
        /* Then create codec instances */
        for (c = 0; c < max_slots; c++) {
                if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) {
                        struct hda_codec *codec;
-                       err = snd_hda_codec_new(chip->bus, c, &codec);
+                       err = snd_hda_codec_new(bus, bus->card, c, &codec);
                        if (err < 0)
                                continue;
                        codec->jackpoll_interval = get_jackpoll_interval(chip);
@@ -1900,7 +1907,7 @@ int azx_codec_create(struct azx *chip, const char *model,
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(azx_codec_create);
+EXPORT_SYMBOL_GPL(azx_probe_codecs);
 
 /* configure each codec instance */
 int azx_codec_configure(struct azx *chip)
@@ -1913,13 +1920,6 @@ int azx_codec_configure(struct azx *chip)
 }
 EXPORT_SYMBOL_GPL(azx_codec_configure);
 
-/* mixer creation - all stuff is implemented in hda module */
-int azx_mixer_create(struct azx *chip)
-{
-       return snd_hda_build_controls(chip->bus);
-}
-EXPORT_SYMBOL_GPL(azx_mixer_create);
-
 
 static bool is_input_stream(struct azx *chip, unsigned char index)
 {
@@ -1966,30 +1966,5 @@ int azx_init_stream(struct azx *chip)
 }
 EXPORT_SYMBOL_GPL(azx_init_stream);
 
-/*
- * reboot notifier for hang-up problem at power-down
- */
-static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf)
-{
-       struct azx *chip = container_of(nb, struct azx, reboot_notifier);
-       snd_hda_bus_reboot_notify(chip->bus);
-       azx_stop_chip(chip);
-       return NOTIFY_OK;
-}
-
-void azx_notifier_register(struct azx *chip)
-{
-       chip->reboot_notifier.notifier_call = azx_halt;
-       register_reboot_notifier(&chip->reboot_notifier);
-}
-EXPORT_SYMBOL_GPL(azx_notifier_register);
-
-void azx_notifier_unregister(struct azx *chip)
-{
-       if (chip->reboot_notifier.notifier_call)
-               unregister_reboot_notifier(&chip->reboot_notifier);
-}
-EXPORT_SYMBOL_GPL(azx_notifier_unregister);
-
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Common HDA driver functions");
index c90d10fd4d8fc2d1317f878f60a008e709c56260..be1b7ded8d8202f43282611f0549d20577f75f98 100644 (file)
 #ifndef __SOUND_HDA_CONTROLLER_H
 #define __SOUND_HDA_CONTROLLER_H
 
+#include <linux/timecounter.h>
+#include <linux/interrupt.h>
 #include <sound/core.h>
+#include <sound/pcm.h>
 #include <sound/initval.h>
 #include "hda_codec.h"
-#include "hda_priv.h"
+
+/*
+ * registers
+ */
+#define AZX_REG_GCAP                   0x00
+#define   AZX_GCAP_64OK                (1 << 0)   /* 64bit address support */
+#define   AZX_GCAP_NSDO                (3 << 1)   /* # of serial data out signals */
+#define   AZX_GCAP_BSS         (31 << 3)  /* # of bidirectional streams */
+#define   AZX_GCAP_ISS         (15 << 8)  /* # of input streams */
+#define   AZX_GCAP_OSS         (15 << 12) /* # of output streams */
+#define AZX_REG_VMIN                   0x02
+#define AZX_REG_VMAJ                   0x03
+#define AZX_REG_OUTPAY                 0x04
+#define AZX_REG_INPAY                  0x06
+#define AZX_REG_GCTL                   0x08
+#define   AZX_GCTL_RESET       (1 << 0)   /* controller reset */
+#define   AZX_GCTL_FCNTRL      (1 << 1)   /* flush control */
+#define   AZX_GCTL_UNSOL       (1 << 8)   /* accept unsol. response enable */
+#define AZX_REG_WAKEEN                 0x0c
+#define AZX_REG_STATESTS               0x0e
+#define AZX_REG_GSTS                   0x10
+#define   AZX_GSTS_FSTS                (1 << 1)   /* flush status */
+#define AZX_REG_INTCTL                 0x20
+#define AZX_REG_INTSTS                 0x24
+#define AZX_REG_WALLCLK                        0x30    /* 24Mhz source */
+#define AZX_REG_OLD_SSYNC              0x34    /* SSYNC for old ICH */
+#define AZX_REG_SSYNC                  0x38
+#define AZX_REG_CORBLBASE              0x40
+#define AZX_REG_CORBUBASE              0x44
+#define AZX_REG_CORBWP                 0x48
+#define AZX_REG_CORBRP                 0x4a
+#define   AZX_CORBRP_RST       (1 << 15)  /* read pointer reset */
+#define AZX_REG_CORBCTL                        0x4c
+#define   AZX_CORBCTL_RUN      (1 << 1)   /* enable DMA */
+#define   AZX_CORBCTL_CMEIE    (1 << 0)   /* enable memory error irq */
+#define AZX_REG_CORBSTS                        0x4d
+#define   AZX_CORBSTS_CMEI     (1 << 0)   /* memory error indication */
+#define AZX_REG_CORBSIZE               0x4e
+
+#define AZX_REG_RIRBLBASE              0x50
+#define AZX_REG_RIRBUBASE              0x54
+#define AZX_REG_RIRBWP                 0x58
+#define   AZX_RIRBWP_RST       (1 << 15)  /* write pointer reset */
+#define AZX_REG_RINTCNT                        0x5a
+#define AZX_REG_RIRBCTL                        0x5c
+#define   AZX_RBCTL_IRQ_EN     (1 << 0)   /* enable IRQ */
+#define   AZX_RBCTL_DMA_EN     (1 << 1)   /* enable DMA */
+#define   AZX_RBCTL_OVERRUN_EN (1 << 2)   /* enable overrun irq */
+#define AZX_REG_RIRBSTS                        0x5d
+#define   AZX_RBSTS_IRQ                (1 << 0)   /* response irq */
+#define   AZX_RBSTS_OVERRUN    (1 << 2)   /* overrun irq */
+#define AZX_REG_RIRBSIZE               0x5e
+
+#define AZX_REG_IC                     0x60
+#define AZX_REG_IR                     0x64
+#define AZX_REG_IRS                    0x68
+#define   AZX_IRS_VALID                (1<<1)
+#define   AZX_IRS_BUSY         (1<<0)
+
+#define AZX_REG_DPLBASE                        0x70
+#define AZX_REG_DPUBASE                        0x74
+#define   AZX_DPLBASE_ENABLE   0x1     /* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define AZX_REG_SD_CTL                 0x00
+#define AZX_REG_SD_STS                 0x03
+#define AZX_REG_SD_LPIB                        0x04
+#define AZX_REG_SD_CBL                 0x08
+#define AZX_REG_SD_LVI                 0x0c
+#define AZX_REG_SD_FIFOW               0x0e
+#define AZX_REG_SD_FIFOSIZE            0x10
+#define AZX_REG_SD_FORMAT              0x12
+#define AZX_REG_SD_BDLPL               0x18
+#define AZX_REG_SD_BDLPU               0x1c
+
+/* PCI space */
+#define AZX_PCIREG_TCSEL               0x44
+
+/*
+ * other constants
+ */
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE               4096
+#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
+#define AZX_MAX_FRAG           32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE       (1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE      0x01
+#define RIRB_INT_OVERRUN       0x04
+#define RIRB_INT_MASK          0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS         8
+#define AZX_DEFAULT_CODECS     4
+#define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
+#define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
+#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
+#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
+#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT        20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
+#define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
+#define SD_INT_COMPLETE                0x04    /* completion interrupt */
+#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+                                SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY      0x20    /* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define AZX_INT_ALL_STREAM     0xff       /* all stream interrupts */
+#define AZX_INT_CTRL_EN        0x40000000 /* controller interrupt enable bit */
+#define AZX_INT_GLOBAL_EN      0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define AZX_MAX_CORB_ENTRIES   256
+#define AZX_MAX_RIRB_ENTRIES   256
+
+/* driver quirks (capabilities) */
+/* bits 0-7 are used for indicating driver type */
+#define AZX_DCAPS_NO_TCSEL     (1 << 8)        /* No Intel TCSEL bit */
+#define AZX_DCAPS_NO_MSI       (1 << 9)        /* No MSI support */
+#define AZX_DCAPS_SNOOP_MASK   (3 << 10)       /* snoop type mask */
+#define AZX_DCAPS_SNOOP_OFF    (1 << 12)       /* snoop default off */
+#define AZX_DCAPS_RIRB_DELAY   (1 << 13)       /* Long delay in read loop */
+#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)     /* Put a delay before read */
+#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
+#define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
+#define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
+#define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
+#define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
+#define AZX_DCAPS_OLD_SSYNC    (1 << 20)       /* Old SSYNC reg for ICH */
+#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21)   /* no buffer size alignment */
+/* 22 unused */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)   /* BDLE in 4k boundary */
+#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24)     /* Assign devices in reverse order */
+#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)  /* Take LPIB as delay */
+#define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
+#define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 powerwell support */
+#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)  /* CORBRP clears itself after reset */
+#define AZX_DCAPS_NO_MSI64      (1 << 29)      /* Stick to 32-bit MSIs */
+#define AZX_DCAPS_SEPARATE_STREAM_TAG  (1 << 30) /* capture and playback use separate stream tag */
+
+enum {
+       AZX_SNOOP_TYPE_NONE,
+       AZX_SNOOP_TYPE_SCH,
+       AZX_SNOOP_TYPE_ATI,
+       AZX_SNOOP_TYPE_NVIDIA,
+};
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
+
+struct azx_dev {
+       struct snd_dma_buffer bdl; /* BDL buffer */
+       u32 *posbuf;            /* position buffer pointer */
+
+       unsigned int bufsize;   /* size of the play buffer in bytes */
+       unsigned int period_bytes; /* size of the period in bytes */
+       unsigned int frags;     /* number for period in the play buffer */
+       unsigned int fifo_size; /* FIFO size */
+       unsigned long start_wallclk;    /* start + minimum wallclk */
+       unsigned long period_wallclk;   /* wallclk for period */
+
+       void __iomem *sd_addr;  /* stream descriptor pointer */
+
+       u32 sd_int_sta_mask;    /* stream int status mask */
+
+       /* pcm support */
+       struct snd_pcm_substream *substream;    /* assigned substream,
+                                                * set in PCM open
+                                                */
+       unsigned int format_val;        /* format value to be set in the
+                                        * controller and the codec
+                                        */
+       unsigned char stream_tag;       /* assigned stream */
+       unsigned char index;            /* stream index */
+       int assigned_key;               /* last device# key assigned to */
+
+       unsigned int opened:1;
+       unsigned int running:1;
+       unsigned int irq_pending:1;
+       unsigned int prepared:1;
+       unsigned int locked:1;
+       /*
+        * For VIA:
+        *  A flag to ensure DMA position is 0
+        *  when link position is not greater than FIFO size
+        */
+       unsigned int insufficient:1;
+       unsigned int wc_marked:1;
+       unsigned int no_period_wakeup:1;
+
+       struct timecounter  azx_tc;
+       struct cyclecounter azx_cc;
+
+       int delay_negative_threshold;
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+       /* Allows dsp load to have sole access to the playback stream. */
+       struct mutex dsp_mutex;
+#endif
+};
+
+/* CORB/RIRB */
+struct azx_rb {
+       u32 *buf;               /* CORB/RIRB buffer
+                                * Each CORB entry is 4byte, RIRB is 8byte
+                                */
+       dma_addr_t addr;        /* physical address of CORB/RIRB buffer */
+       /* for RIRB */
+       unsigned short rp, wp;  /* read/write pointers */
+       int cmds[AZX_MAX_CODECS];       /* number of pending requests */
+       u32 res[AZX_MAX_CODECS];        /* last read value */
+};
+
+struct azx;
+
+/* Functions to read/write to hda registers. */
+struct hda_controller_ops {
+       /* Register Access */
+       void (*reg_writel)(u32 value, u32 __iomem *addr);
+       u32 (*reg_readl)(u32 __iomem *addr);
+       void (*reg_writew)(u16 value, u16 __iomem *addr);
+       u16 (*reg_readw)(u16 __iomem *addr);
+       void (*reg_writeb)(u8 value, u8 __iomem *addr);
+       u8 (*reg_readb)(u8 __iomem *addr);
+       /* Disable msi if supported, PCI only */
+       int (*disable_msi_reset_irq)(struct azx *);
+       /* Allocation ops */
+       int (*dma_alloc_pages)(struct azx *chip,
+                              int type,
+                              size_t size,
+                              struct snd_dma_buffer *buf);
+       void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf);
+       int (*substream_alloc_pages)(struct azx *chip,
+                                    struct snd_pcm_substream *substream,
+                                    size_t size);
+       int (*substream_free_pages)(struct azx *chip,
+                                   struct snd_pcm_substream *substream);
+       void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
+                                struct vm_area_struct *area);
+       /* Check if current position is acceptable */
+       int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
+};
+
+struct azx_pcm {
+       struct azx *chip;
+       struct snd_pcm *pcm;
+       struct hda_codec *codec;
+       struct hda_pcm *info;
+       struct list_head list;
+};
+
+typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *);
+typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos);
+
+struct azx {
+       struct snd_card *card;
+       struct pci_dev *pci;
+       int dev_index;
+
+       /* chip type specific */
+       int driver_type;
+       unsigned int driver_caps;
+       int playback_streams;
+       int playback_index_offset;
+       int capture_streams;
+       int capture_index_offset;
+       int num_streams;
+       const int *jackpoll_ms; /* per-card jack poll interval */
+
+       /* Register interaction. */
+       const struct hda_controller_ops *ops;
+
+       /* position adjustment callbacks */
+       azx_get_pos_callback_t get_position[2];
+       azx_get_delay_callback_t get_delay[2];
+
+       /* pci resources */
+       unsigned long addr;
+       void __iomem *remap_addr;
+       int irq;
+
+       /* locks */
+       spinlock_t reg_lock;
+       struct mutex open_mutex; /* Prevents concurrent open/close operations */
+
+       /* streams (x num_streams) */
+       struct azx_dev *azx_dev;
+
+       /* PCM */
+       struct list_head pcm_list; /* azx_pcm list */
+
+       /* HD codec */
+       unsigned short codec_mask;
+       int  codec_probe_mask; /* copied from probe_mask option */
+       struct hda_bus *bus;
+       unsigned int beep_mode;
+
+       /* CORB/RIRB */
+       struct azx_rb corb;
+       struct azx_rb rirb;
+
+       /* CORB/RIRB and position buffers */
+       struct snd_dma_buffer rb;
+       struct snd_dma_buffer posbuf;
+
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       const struct firmware *fw;
+#endif
+
+       /* flags */
+       const int *bdl_pos_adj;
+       int poll_count;
+       unsigned int running:1;
+       unsigned int initialized:1;
+       unsigned int single_cmd:1;
+       unsigned int polling_mode:1;
+       unsigned int msi:1;
+       unsigned int probing:1; /* codec probing phase */
+       unsigned int snoop:1;
+       unsigned int align_buffer_size:1;
+       unsigned int region_requested:1;
+       unsigned int disabled:1; /* disabled by VGA-switcher */
+
+       /* for debugging */
+       unsigned int last_cmd[AZX_MAX_CODECS];
+
+#ifdef CONFIG_SND_HDA_DSP_LOADER
+       struct azx_dev saved_azx_dev;
+#endif
+};
+
+#ifdef CONFIG_X86
+#define azx_snoop(chip)                ((chip)->snoop)
+#else
+#define azx_snoop(chip)                true
+#endif
+
+/*
+ * macros for easy use
+ */
+
+#define azx_writel(chip, reg, value) \
+       ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readl(chip, reg) \
+       ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg))
+#define azx_writew(chip, reg, value) \
+       ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readw(chip, reg) \
+       ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg))
+#define azx_writeb(chip, reg, value) \
+       ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg))
+#define azx_readb(chip, reg) \
+       ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg))
+
+#define azx_sd_writel(chip, dev, reg, value) \
+       ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readl(chip, dev, reg) \
+       ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_writew(chip, dev, reg, value) \
+       ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readw(chip, dev, reg) \
+       ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_writeb(chip, dev, reg, value) \
+       ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg))
+#define azx_sd_readb(chip, dev, reg) \
+       ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg))
+
+#define azx_has_pm_runtime(chip) \
+       (!AZX_DCAPS_PM_RUNTIME || ((chip)->driver_caps & AZX_DCAPS_PM_RUNTIME))
 
 /* PCM setup */
 static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream)
@@ -43,14 +429,9 @@ void azx_enter_link_reset(struct azx *chip);
 irqreturn_t azx_interrupt(int irq, void *dev_id);
 
 /* Codec interface */
-int azx_codec_create(struct azx *chip, const char *model,
-                    unsigned int max_slots,
-                    int *power_save_to);
+int azx_bus_create(struct azx *chip, const char *model);
+int azx_probe_codecs(struct azx *chip, unsigned int max_slots);
 int azx_codec_configure(struct azx *chip);
-int azx_mixer_create(struct azx *chip);
 int azx_init_stream(struct azx *chip);
 
-void azx_notifier_register(struct azx *chip);
-void azx_notifier_unregister(struct azx *chip);
-
 #endif /* __SOUND_HDA_CONTROLLER_H */
index 8ec5289f8e058538892aa04c402a4db9967c94c7..0ef2459cd05fd6468a1ec6ee7d04a02bdb971fda 100644 (file)
@@ -140,6 +140,9 @@ static void parse_user_hints(struct hda_codec *codec)
        val = snd_hda_get_bool_hint(codec, "single_adc_amp");
        if (val >= 0)
                codec->single_adc_amp = !!val;
+       val = snd_hda_get_bool_hint(codec, "power_save_node");
+       if (val >= 0)
+               codec->power_save_node = !!val;
 
        val = snd_hda_get_bool_hint(codec, "auto_mute");
        if (val >= 0)
@@ -648,12 +651,24 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
                          unsigned int dir, unsigned int idx)
 {
        struct hda_gen_spec *spec = codec->spec;
+       int type = get_wcaps_type(get_wcaps(codec, nid));
        int i, n;
 
+       if (nid == codec->afg)
+               return true;
+
        for (n = 0; n < spec->paths.used; n++) {
                struct nid_path *path = snd_array_elem(&spec->paths, n);
                if (!path->active)
                        continue;
+               if (codec->power_save_node) {
+                       if (!path->stream_enabled)
+                               continue;
+                       /* ignore unplugged paths except for DAC/ADC */
+                       if (!(path->pin_enabled || path->pin_fixed) &&
+                           type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN)
+                               continue;
+               }
                for (i = 0; i < path->depth; i++) {
                        if (path->path[i] == nid) {
                                if (dir == HDA_OUTPUT || path->idx[i] == idx)
@@ -807,6 +822,44 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
        }
 }
 
+/* sync power of each widget in the the given path */
+static hda_nid_t path_power_update(struct hda_codec *codec,
+                                  struct nid_path *path,
+                                  bool allow_powerdown)
+{
+       hda_nid_t nid, changed = 0;
+       int i, state;
+
+       for (i = 0; i < path->depth; i++) {
+               nid = path->path[i];
+               if (nid == codec->afg)
+                       continue;
+               if (!allow_powerdown || is_active_nid_for_any(codec, nid))
+                       state = AC_PWRST_D0;
+               else
+                       state = AC_PWRST_D3;
+               if (!snd_hda_check_power_state(codec, nid, state)) {
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_POWER_STATE, state);
+                       changed = nid;
+                       /* here we assume that widget attributes (e.g. amp,
+                        * pinctl connection) don't change with local power
+                        * state change.  If not, need to sync the cache.
+                        */
+               }
+       }
+       return changed;
+}
+
+/* do sync with the last power state change */
+static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid)
+{
+       if (nid) {
+               msleep(10);
+               snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+       }
+}
+
 /**
  * snd_hda_activate_path - activate or deactivate the given path
  * @codec: the HDA codec
@@ -825,15 +878,13 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
        if (!enable)
                path->active = false;
 
+       /* make sure the widget is powered up */
+       if (enable && (spec->power_down_unused || codec->power_save_node))
+               path_power_update(codec, path, codec->power_save_node);
+
        for (i = path->depth - 1; i >= 0; i--) {
                hda_nid_t nid = path->path[i];
-               if (enable && spec->power_down_unused) {
-                       /* make sure the widget is powered up */
-                       if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0))
-                               snd_hda_codec_write(codec, nid, 0,
-                                                   AC_VERB_SET_POWER_STATE,
-                                                   AC_PWRST_D0);
-               }
+
                if (enable && path->multi[i])
                        snd_hda_codec_update_cache(codec, nid, 0,
                                            AC_VERB_SET_CONNECT_SEL,
@@ -853,28 +904,10 @@ EXPORT_SYMBOL_GPL(snd_hda_activate_path);
 static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
 {
        struct hda_gen_spec *spec = codec->spec;
-       bool changed = false;
-       int i;
 
-       if (!spec->power_down_unused || path->active)
+       if (!(spec->power_down_unused || codec->power_save_node) || path->active)
                return;
-
-       for (i = 0; i < path->depth; i++) {
-               hda_nid_t nid = path->path[i];
-               if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3) &&
-                   !is_active_nid_for_any(codec, nid)) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D3);
-                       changed = true;
-               }
-       }
-
-       if (changed) {
-               msleep(10);
-               snd_hda_codec_read(codec, path->path[0], 0,
-                                  AC_VERB_GET_POWER_STATE, 0);
-       }
+       sync_power_state_change(codec, path_power_update(codec, path, true));
 }
 
 /* turn on/off EAPD on the given pin */
@@ -1574,6 +1607,7 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
                return 0;
        /* print_nid_path(codec, "output-aamix", path); */
        path->active = false; /* unused as default */
+       path->pin_fixed = true; /* static route */
        return snd_hda_get_path_idx(codec, path);
 }
 
@@ -2998,6 +3032,7 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
        }
 
        path->active = true;
+       path->stream_enabled = true; /* no DAC/ADC involved */
        err = add_loopback_list(spec, mix_nid, idx);
        if (err < 0)
                return err;
@@ -3009,6 +3044,8 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
                if (path) {
                        print_nid_path(codec, "loopback-merge", path);
                        path->active = true;
+                       path->pin_fixed = true; /* static route */
+                       path->stream_enabled = true; /* no DAC/ADC involved */
                        spec->loopback_merge_path =
                                snd_hda_get_path_idx(codec, path);
                }
@@ -3810,6 +3847,7 @@ static void parse_digital(struct hda_codec *codec)
                        continue;
                print_nid_path(codec, "digout", path);
                path->active = true;
+               path->pin_fixed = true; /* no jack detection */
                spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
                set_pin_target(codec, pin, PIN_OUT, false);
                if (!nums) {
@@ -3837,6 +3875,7 @@ static void parse_digital(struct hda_codec *codec)
                        if (path) {
                                print_nid_path(codec, "digin", path);
                                path->active = true;
+                               path->pin_fixed = true; /* no jack */
                                spec->dig_in_nid = dig_nid;
                                spec->digin_path = snd_hda_get_path_idx(codec, path);
                                set_pin_target(codec, pin, PIN_IN, false);
@@ -3896,6 +3935,229 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
        return 1;
 }
 
+/* power up/down widgets in the all paths that match with the given NID
+ * as terminals (either start- or endpoint)
+ *
+ * returns the last changed NID, or zero if unchanged.
+ */
+static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid,
+                               int pin_state, int stream_state)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t last, changed = 0;
+       struct nid_path *path;
+       int n;
+
+       for (n = 0; n < spec->paths.used; n++) {
+               path = snd_array_elem(&spec->paths, n);
+               if (path->path[0] == nid ||
+                   path->path[path->depth - 1] == nid) {
+                       bool pin_old = path->pin_enabled;
+                       bool stream_old = path->stream_enabled;
+
+                       if (pin_state >= 0)
+                               path->pin_enabled = pin_state;
+                       if (stream_state >= 0)
+                               path->stream_enabled = stream_state;
+                       if ((!path->pin_fixed && path->pin_enabled != pin_old)
+                           || path->stream_enabled != stream_old) {
+                               last = path_power_update(codec, path, true);
+                               if (last)
+                                       changed = last;
+                       }
+               }
+       }
+       return changed;
+}
+
+/* power up/down the paths of the given pin according to the jack state;
+ * power = 0/1 : only power up/down if it matches with the jack state,
+ *       < 0   : force power up/down to follow the jack sate
+ *
+ * returns the last changed NID, or zero if unchanged.
+ */
+static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin,
+                                   int power)
+{
+       bool on;
+
+       if (!codec->power_save_node)
+               return 0;
+
+       on = snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
+       if (power >= 0 && on != power)
+               return 0;
+       return set_path_power(codec, pin, on, -1);
+}
+
+static void pin_power_callback(struct hda_codec *codec,
+                              struct hda_jack_callback *jack,
+                              bool on)
+{
+       if (jack && jack->tbl->nid)
+               sync_power_state_change(codec,
+                                       set_pin_power_jack(codec, jack->tbl->nid, on));
+}
+
+/* callback only doing power up -- called at first */
+static void pin_power_up_callback(struct hda_codec *codec,
+                                 struct hda_jack_callback *jack)
+{
+       pin_power_callback(codec, jack, true);
+}
+
+/* callback only doing power down -- called at last */
+static void pin_power_down_callback(struct hda_codec *codec,
+                                   struct hda_jack_callback *jack)
+{
+       pin_power_callback(codec, jack, false);
+}
+
+/* set up the power up/down callbacks */
+static void add_pin_power_ctls(struct hda_codec *codec, int num_pins,
+                              const hda_nid_t *pins, bool on)
+{
+       int i;
+       hda_jack_callback_fn cb =
+               on ? pin_power_up_callback : pin_power_down_callback;
+
+       for (i = 0; i < num_pins && pins[i]; i++) {
+               if (is_jack_detectable(codec, pins[i]))
+                       snd_hda_jack_detect_enable_callback(codec, pins[i], cb);
+               else
+                       set_path_power(codec, pins[i], true, -1);
+       }
+}
+
+/* enabled power callback to each available I/O pin with jack detections;
+ * the digital I/O pins are excluded because of the unreliable detectsion
+ */
+static void add_all_pin_power_ctls(struct hda_codec *codec, bool on)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       if (!codec->power_save_node)
+               return;
+       add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on);
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+               add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on);
+       for (i = 0; i < cfg->num_inputs; i++)
+               add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on);
+}
+
+/* sync path power up/down with the jack states of given pins */
+static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins,
+                               const hda_nid_t *pins)
+{
+       int i;
+
+       for (i = 0; i < num_pins && pins[i]; i++)
+               if (is_jack_detectable(codec, pins[i]))
+                       set_pin_power_jack(codec, pins[i], -1);
+}
+
+/* sync path power up/down with pins; called at init and resume */
+static void sync_all_pin_power_ctls(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       if (!codec->power_save_node)
+               return;
+       sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins);
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+               sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins);
+       for (i = 0; i < cfg->num_inputs; i++)
+               sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
+}
+
+/* add fake paths if not present yet */
+static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
+                          int num_pins, const hda_nid_t *pins)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       int i;
+
+       for (i = 0; i < num_pins; i++) {
+               if (!pins[i])
+                       break;
+               if (get_nid_path(codec, nid, pins[i], 0))
+                       continue;
+               path = snd_array_new(&spec->paths);
+               if (!path)
+                       return -ENOMEM;
+               memset(path, 0, sizeof(*path));
+               path->depth = 2;
+               path->path[0] = nid;
+               path->path[1] = pins[i];
+               path->active = true;
+       }
+       return 0;
+}
+
+/* create fake paths to all outputs from beep */
+static int add_fake_beep_paths(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid = spec->beep_nid;
+       int err;
+
+       if (!codec->power_save_node || !nid)
+               return 0;
+       err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
+       if (err < 0)
+               return err;
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+               err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
+               if (err < 0)
+                       return err;
+       }
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               err = add_fake_paths(codec, nid, cfg->speaker_outs,
+                                    cfg->speaker_pins);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/* power up/down beep widget and its output paths */
+static void beep_power_hook(struct hda_beep *beep, bool on)
+{
+       set_path_power(beep->codec, beep->nid, -1, on);
+}
+
+/**
+ * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0
+ * @codec: the HDA codec
+ * @pin: NID of pin to fix
+ */
+int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+
+       path = snd_array_new(&spec->paths);
+       if (!path)
+               return -ENOMEM;
+       memset(path, 0, sizeof(*path));
+       path->depth = 1;
+       path->path[0] = pin;
+       path->active = true;
+       path->pin_fixed = true;
+       path->stream_enabled = true;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power);
 
 /*
  * Jack detections for HP auto-mute and mic-switch
@@ -3933,6 +4195,10 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
                if (!nid)
                        break;
 
+               oldval = snd_hda_codec_get_pin_target(codec, nid);
+               if (oldval & PIN_IN)
+                       continue; /* no mute for inputs */
+
                if (spec->auto_mute_via_amp) {
                        struct nid_path *path;
                        hda_nid_t mute_nid;
@@ -3947,29 +4213,33 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
                                spec->mute_bits |= (1ULL << mute_nid);
                        else
                                spec->mute_bits &= ~(1ULL << mute_nid);
-                       set_pin_eapd(codec, nid, !mute);
                        continue;
+               } else {
+                       /* don't reset VREF value in case it's controlling
+                        * the amp (see alc861_fixup_asus_amp_vref_0f())
+                        */
+                       if (spec->keep_vref_in_automute)
+                               val = oldval & ~PIN_HP;
+                       else
+                               val = 0;
+                       if (!mute)
+                               val |= oldval;
+                       /* here we call update_pin_ctl() so that the pinctl is
+                        * changed without changing the pinctl target value;
+                        * the original target value will be still referred at
+                        * the init / resume again
+                        */
+                       update_pin_ctl(codec, nid, val);
                }
 
-               oldval = snd_hda_codec_get_pin_target(codec, nid);
-               if (oldval & PIN_IN)
-                       continue; /* no mute for inputs */
-               /* don't reset VREF value in case it's controlling
-                * the amp (see alc861_fixup_asus_amp_vref_0f())
-                */
-               if (spec->keep_vref_in_automute)
-                       val = oldval & ~PIN_HP;
-               else
-                       val = 0;
-               if (!mute)
-                       val |= oldval;
-               /* here we call update_pin_ctl() so that the pinctl is changed
-                * without changing the pinctl target value;
-                * the original target value will be still referred at the
-                * init / resume again
-                */
-               update_pin_ctl(codec, nid, val);
                set_pin_eapd(codec, nid, !mute);
+               if (codec->power_save_node) {
+                       bool on = !mute;
+                       if (on)
+                               on = snd_hda_jack_detect_state(codec, nid)
+                                       != HDA_JACK_NOT_PRESENT;
+                       set_path_power(codec, nid, on, -1);
+               }
        }
 }
 
@@ -4465,6 +4735,21 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
        }
 }
 
+/**
+ * snd_hda_gen_stream_pm - Stream power management callback
+ * @codec: the HDA codec
+ * @nid: audio widget
+ * @on: power on/off flag
+ *
+ * Set this in patch_ops.stream_pm.  Only valid with power_save_node flag.
+ */
+void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
+{
+       if (codec->power_save_node)
+               set_path_power(codec, nid, -1, on);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
+
 /**
  * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
  * set up the hda_gen_spec
@@ -4549,6 +4834,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
        if (err < 0)
                return err;
 
+       /* add power-down pin callbacks at first */
+       add_all_pin_power_ctls(codec, false);
+
        spec->const_channel_count = spec->ext_channel_count;
        /* check the multiple speaker and headphone pins */
        if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
@@ -4618,6 +4906,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
                }
        }
 
+       /* add power-up pin callbacks at last */
+       add_all_pin_power_ctls(codec, true);
+
        /* mute all aamix input initially */
        if (spec->mixer_nid)
                mute_all_mixer_nid(codec, spec->mixer_nid);
@@ -4625,13 +4916,19 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
  dig_only:
        parse_digital(codec);
 
-       if (spec->power_down_unused)
+       if (spec->power_down_unused || codec->power_save_node)
                codec->power_filter = snd_hda_gen_path_power_filter;
 
        if (!spec->no_analog && spec->beep_nid) {
                err = snd_hda_attach_beep_device(codec, spec->beep_nid);
                if (err < 0)
                        return err;
+               if (codec->beep && codec->power_save_node) {
+                       err = add_fake_beep_paths(codec);
+                       if (err < 0)
+                               return err;
+                       codec->beep->power_hook = beep_power_hook;
+               }
        }
 
        return 1;
@@ -4675,7 +4972,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
                err = snd_hda_create_dig_out_ctls(codec,
                                                  spec->multiout.dig_out_nid,
                                                  spec->multiout.dig_out_nid,
-                                                 spec->pcm_rec[1].pcm_type);
+                                                 spec->pcm_rec[1]->pcm_type);
                if (err < 0)
                        return err;
                if (!spec->no_analog) {
@@ -5137,6 +5434,33 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
        strlcat(str, sfx, len);
 }
 
+/* copy PCM stream info from @default_str, and override non-NULL entries
+ * from @spec_str and @nid
+ */
+static void setup_pcm_stream(struct hda_pcm_stream *str,
+                            const struct hda_pcm_stream *default_str,
+                            const struct hda_pcm_stream *spec_str,
+                            hda_nid_t nid)
+{
+       *str = *default_str;
+       if (nid)
+               str->nid = nid;
+       if (spec_str) {
+               if (spec_str->substreams)
+                       str->substreams = spec_str->substreams;
+               if (spec_str->channels_min)
+                       str->channels_min = spec_str->channels_min;
+               if (spec_str->channels_max)
+                       str->channels_max = spec_str->channels_max;
+               if (spec_str->rates)
+                       str->rates = spec_str->rates;
+               if (spec_str->formats)
+                       str->formats = spec_str->formats;
+               if (spec_str->maxbps)
+                       str->maxbps = spec_str->maxbps;
+       }
+}
+
 /**
  * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
  * @codec: the HDA codec
@@ -5146,27 +5470,25 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
 int snd_hda_gen_build_pcms(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-       const struct hda_pcm_stream *p;
+       struct hda_pcm *info;
        bool have_multi_adcs;
 
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
        if (spec->no_analog)
                goto skip_analog;
 
        fill_pcm_stream_name(spec->stream_name_analog,
                             sizeof(spec->stream_name_analog),
                             " Analog", codec->chip_name);
-       info->name = spec->stream_name_analog;
+       info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
+       if (!info)
+               return -ENOMEM;
+       spec->pcm_rec[0] = info;
 
        if (spec->multiout.num_dacs > 0) {
-               p = spec->stream_analog_playback;
-               if (!p)
-                       p = &pcm_analog_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+               setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                &pcm_analog_playback,
+                                spec->stream_analog_playback,
+                                spec->multiout.dac_nids[0]);
                info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
                        spec->multiout.max_channels;
                if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
@@ -5175,15 +5497,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
                                snd_pcm_2_1_chmaps;
        }
        if (spec->num_adc_nids) {
-               p = spec->stream_analog_capture;
-               if (!p) {
-                       if (spec->dyn_adc_switch)
-                               p = &dyn_adc_pcm_analog_capture;
-                       else
-                               p = &pcm_analog_capture;
-               }
-               info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
-               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
+               setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                (spec->dyn_adc_switch ?
+                                 &dyn_adc_pcm_analog_capture : &pcm_analog_capture),
+                                spec->stream_analog_capture,
+                                spec->adc_nids[0]);
        }
 
  skip_analog:
@@ -5192,28 +5510,26 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
                fill_pcm_stream_name(spec->stream_name_digital,
                                     sizeof(spec->stream_name_digital),
                                     " Digital", codec->chip_name);
-               codec->num_pcms = 2;
+               info = snd_hda_codec_pcm_new(codec, "%s",
+                                            spec->stream_name_digital);
+               if (!info)
+                       return -ENOMEM;
                codec->slave_dig_outs = spec->multiout.slave_dig_outs;
-               info = spec->pcm_rec + 1;
-               info->name = spec->stream_name_digital;
+               spec->pcm_rec[1] = info;
                if (spec->dig_out_type)
                        info->pcm_type = spec->dig_out_type;
                else
                        info->pcm_type = HDA_PCM_TYPE_SPDIF;
-               if (spec->multiout.dig_out_nid) {
-                       p = spec->stream_digital_playback;
-                       if (!p)
-                               p = &pcm_digital_playback;
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
-               }
-               if (spec->dig_in_nid) {
-                       p = spec->stream_digital_capture;
-                       if (!p)
-                               p = &pcm_digital_capture;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
-               }
+               if (spec->multiout.dig_out_nid)
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                        &pcm_digital_playback,
+                                        spec->stream_digital_playback,
+                                        spec->multiout.dig_out_nid);
+               if (spec->dig_in_nid)
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                        &pcm_digital_capture,
+                                        spec->stream_digital_capture,
+                                        spec->dig_in_nid);
        }
 
        if (spec->no_analog)
@@ -5229,34 +5545,29 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
                fill_pcm_stream_name(spec->stream_name_alt_analog,
                                     sizeof(spec->stream_name_alt_analog),
                             " Alt Analog", codec->chip_name);
-               codec->num_pcms = 3;
-               info = spec->pcm_rec + 2;
-               info->name = spec->stream_name_alt_analog;
-               if (spec->alt_dac_nid) {
-                       p = spec->stream_analog_alt_playback;
-                       if (!p)
-                               p = &pcm_analog_alt_playback;
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
-                               spec->alt_dac_nid;
-               } else {
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                               pcm_null_stream;
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
-               }
+               info = snd_hda_codec_pcm_new(codec, "%s",
+                                            spec->stream_name_alt_analog);
+               if (!info)
+                       return -ENOMEM;
+               spec->pcm_rec[2] = info;
+               if (spec->alt_dac_nid)
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                        &pcm_analog_alt_playback,
+                                        spec->stream_analog_alt_playback,
+                                        spec->alt_dac_nid);
+               else
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                        &pcm_null_stream, NULL, 0);
                if (have_multi_adcs) {
-                       p = spec->stream_analog_alt_capture;
-                       if (!p)
-                               p = &pcm_analog_alt_capture;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
-                               spec->adc_nids[1];
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                        &pcm_analog_alt_capture,
+                                        spec->stream_analog_alt_capture,
+                                        spec->adc_nids[1]);
                        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
                                spec->num_adc_nids - 1;
                } else {
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-                               pcm_null_stream;
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                        &pcm_null_stream, NULL, 0);
                }
        }
 
@@ -5464,6 +5775,8 @@ int snd_hda_gen_init(struct hda_codec *codec)
 
        clear_unsol_on_unused_pins(codec);
 
+       sync_all_pin_power_ctls(codec);
+
        /* call init functions of standard auto-mute helpers */
        update_automute_all(codec);
 
@@ -5524,13 +5837,11 @@ static const struct hda_codec_ops generic_patch_ops = {
 #endif
 };
 
-/**
+/*
  * snd_hda_parse_generic_codec - Generic codec parser
  * @codec: the HDA codec
- *
- * This should be called from the HDA codec core.
  */
-int snd_hda_parse_generic_codec(struct hda_codec *codec)
+static int snd_hda_parse_generic_codec(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec;
        int err;
@@ -5556,7 +5867,17 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec)
        snd_hda_gen_free(codec);
        return err;
 }
-EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec);
+
+static const struct hda_codec_preset snd_hda_preset_generic[] = {
+       { .id = HDA_CODEC_ID_GENERIC, .patch = snd_hda_parse_generic_codec },
+       {} /* terminator */
+};
+
+static struct hda_codec_driver generic_driver = {
+       .preset = snd_hda_preset_generic,
+};
+
+module_hda_codec_driver(generic_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic HD-audio codec parser");
index 3d852660443aafedf7450b39692b70aa1d59921a..56e4139b90320c8b9536458aafbb2a6f045dff57 100644 (file)
@@ -46,7 +46,10 @@ struct nid_path {
        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;
+       bool active:1;          /* activated by driver */
+       bool pin_enabled:1;     /* pins are enabled */
+       bool pin_fixed:1;       /* path with fixed pin */
+       bool stream_enabled:1;  /* stream is active */
 };
 
 /* mic/line-in auto switching entry */
@@ -144,7 +147,7 @@ struct hda_gen_spec {
        int const_channel_count;        /* channel count for all */
 
        /* PCM information */
-       struct hda_pcm pcm_rec[3];      /* used in build_pcms() */
+       struct hda_pcm *pcm_rec[3];     /* used in build_pcms() */
 
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
@@ -340,5 +343,7 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
 unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
                                           hda_nid_t nid,
                                           unsigned int power_state);
+void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
+int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
 
 #endif /* __SOUND_HDA_GENERIC_H */
index 11b5a42b4ec8cf33571631b8ceab890b29f31a15..57df06e76968ac4abd0f00b3005c416af256cb7b 100644 (file)
@@ -101,7 +101,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
        int err;
 
        sprintf(hwname, "HDA Codec %d", codec->addr);
-       err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep);
+       err = snd_hwdep_new(codec->card, hwname, codec->addr, &hwdep);
        if (err < 0)
                return err;
        codec->hwdep = hwdep;
@@ -116,9 +116,6 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
        hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat;
 #endif
 
-       /* link to codec */
-       hwdep->dev.parent = &codec->dev;
-
        /* for sysfs */
        hwdep->dev.groups = snd_hda_dev_attr_groups;
        dev_set_drvdata(&hwdep->dev, codec);
index 714894527e06a50c9dc3903928b610b8a7035423..52a85d87c23c58ae11cd8985d4a50d808ffe3731 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/component.h>
 #include <drm/i915_component.h>
 #include <sound/core.h>
-#include "hda_priv.h"
+#include "hda_controller.h"
 #include "hda_intel.h"
 
 /* Intel HSW/BDW display HDA controller Extended Mode registers.
index 4ca3d5d02436daf0ec7ec7274c675c4beae74423..060f7a2b1aeb4f04809bf70e9ccbf71a999638c2 100644 (file)
@@ -62,7 +62,6 @@
 #include <linux/firmware.h>
 #include "hda_codec.h"
 #include "hda_controller.h"
-#include "hda_priv.h"
 #include "hda_intel.h"
 
 /* position fix mode */
@@ -174,7 +173,6 @@ static struct kernel_param_ops param_ops_xint = {
 #define param_check_xint param_check_int
 
 static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
-static int *power_save_addr = &power_save;
 module_param(power_save, xint, 0644);
 MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
                 "(in second, 0 = disable).");
@@ -187,7 +185,7 @@ static bool power_save_controller = 1;
 module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #else
-static int *power_save_addr;
+#define power_save     0
 #endif /* CONFIG_PM */
 
 static int align_buffer_size = -1;
@@ -530,10 +528,10 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
        if (ok == 1) {
                azx_dev->irq_pending = 0;
                return ok;
-       } else if (ok == 0 && chip->bus && chip->bus->workq) {
+       } else if (ok == 0) {
                /* bogus IRQ, process it later */
                azx_dev->irq_pending = 1;
-               queue_work(chip->bus->workq, &hda->irq_pending_work);
+               schedule_work(&hda->irq_pending_work);
        }
        return 0;
 }
@@ -741,7 +739,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
 {
        struct hda_intel *hda;
        struct azx *chip;
-       struct hda_codec *c;
        int prev = power_save;
        int ret = param_set_int(val, kp);
 
@@ -753,8 +750,7 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
                chip = &hda->chip;
                if (!chip->bus || chip->disabled)
                        continue;
-               list_for_each_entry(c, &chip->bus->codec_list, list)
-                       snd_hda_power_sync(c);
+               snd_hda_set_power_save(chip->bus, power_save * 1000);
        }
        mutex_unlock(&card_list_lock);
        return 0;
@@ -773,7 +769,6 @@ static int azx_suspend(struct device *dev)
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
        struct hda_intel *hda;
-       struct azx_pcm *p;
 
        if (!card)
                return 0;
@@ -785,10 +780,6 @@ static int azx_suspend(struct device *dev)
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        azx_clear_irq_pending(chip);
-       list_for_each_entry(p, &chip->pcm_list, list)
-               snd_pcm_suspend_all(p->pcm);
-       if (chip->initialized)
-               snd_hda_suspend(chip->bus);
        azx_stop_chip(chip);
        azx_enter_link_reset(chip);
        if (chip->irq >= 0) {
@@ -831,7 +822,6 @@ static int azx_resume(struct device *dev)
 
        azx_init_chip(chip, true);
 
-       snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
@@ -852,7 +842,7 @@ static int azx_runtime_suspend(struct device *dev)
        if (chip->disabled || hda->init_failed)
                return 0;
 
-       if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+       if (!azx_has_pm_runtime(chip))
                return 0;
 
        /* enable controller wake up event */
@@ -885,7 +875,7 @@ static int azx_runtime_resume(struct device *dev)
        if (chip->disabled || hda->init_failed)
                return 0;
 
-       if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+       if (!azx_has_pm_runtime(chip))
                return 0;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
@@ -903,8 +893,8 @@ static int azx_runtime_resume(struct device *dev)
        if (status && bus) {
                list_for_each_entry(codec, &bus->codec_list, list)
                        if (status & (1 << codec->addr))
-                               queue_delayed_work(codec->bus->workq,
-                                                  &codec->jackpoll_work, codec->jackpoll_interval);
+                               schedule_delayed_work(&codec->jackpoll_work,
+                                                     codec->jackpoll_interval);
        }
 
        /* disable controller Wake Up event*/
@@ -928,8 +918,8 @@ static int azx_runtime_idle(struct device *dev)
        if (chip->disabled || hda->init_failed)
                return 0;
 
-       if (!power_save_controller ||
-           !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+       if (!power_save_controller || !azx_has_pm_runtime(chip) ||
+           chip->bus->codec_powered)
                return -EBUSY;
 
        return 0;
@@ -1071,14 +1061,11 @@ static int azx_free(struct azx *chip)
        struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
        int i;
 
-       if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
-                       && chip->running)
+       if (azx_has_pm_runtime(chip) && chip->running)
                pm_runtime_get_noresume(&pci->dev);
 
        azx_del_card_list(chip);
 
-       azx_notifier_unregister(chip);
-
        hda->init_failed = 1; /* to be sure */
        complete_all(&hda->probe_wait);
 
@@ -1394,7 +1381,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
 
        hda = kzalloc(sizeof(*hda), GFP_KERNEL);
        if (!hda) {
-               dev_err(card->dev, "Cannot allocate hda\n");
                pci_disable_device(pci);
                return -ENOMEM;
        }
@@ -1575,10 +1561,8 @@ static int azx_first_init(struct azx *chip)
        chip->num_streams = chip->playback_streams + chip->capture_streams;
        chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
                                GFP_KERNEL);
-       if (!chip->azx_dev) {
-               dev_err(card->dev, "cannot malloc azx_dev\n");
+       if (!chip->azx_dev)
                return -ENOMEM;
-       }
 
        err = azx_alloc_stream_pages(chip);
        if (err < 0)
@@ -1615,19 +1599,6 @@ static int azx_first_init(struct azx *chip)
        return 0;
 }
 
-static void power_down_all_codecs(struct azx *chip)
-{
-#ifdef CONFIG_PM
-       /* The codecs were powered up in snd_hda_codec_new().
-        * Now all initialization done, so turn them down if possible
-        */
-       struct hda_codec *codec;
-       list_for_each_entry(codec, &chip->bus->codec_list, list) {
-               snd_hda_power_down(codec);
-       }
-#endif
-}
-
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 /* callback from request_firmware_nowait() */
 static void azx_firmware_cb(const struct firmware *fw, void *context)
@@ -1896,12 +1867,14 @@ static int azx_probe_continue(struct azx *chip)
 #endif
 
        /* create codec instances */
-       err = azx_codec_create(chip, model[dev],
-                              azx_max_codecs[chip->driver_type],
-                              power_save_addr);
+       err = azx_bus_create(chip, model[dev]);
+       if (err < 0)
+               goto out_free;
 
+       err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]);
        if (err < 0)
                goto out_free;
+
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
        if (chip->fw) {
                err = snd_hda_load_patch(chip->bus, chip->fw->size,
@@ -1920,25 +1893,14 @@ static int azx_probe_continue(struct azx *chip)
                        goto out_free;
        }
 
-       /* create PCM streams */
-       err = snd_hda_build_pcms(chip->bus);
-       if (err < 0)
-               goto out_free;
-
-       /* create mixer controls */
-       err = azx_mixer_create(chip);
-       if (err < 0)
-               goto out_free;
-
        err = snd_card_register(chip->card);
        if (err < 0)
                goto out_free;
 
        chip->running = 1;
-       power_down_all_codecs(chip);
-       azx_notifier_register(chip);
        azx_add_card_list(chip);
-       if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || hda->use_vga_switcheroo)
+       snd_hda_set_power_save(chip->bus, power_save * 1000);
+       if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
                pm_runtime_put_noidle(&pci->dev);
 
 out_free:
@@ -1956,6 +1918,18 @@ static void azx_remove(struct pci_dev *pci)
                snd_card_free(card);
 }
 
+static void azx_shutdown(struct pci_dev *pci)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct azx *chip;
+
+       if (!card)
+               return;
+       chip = card->private_data;
+       if (chip && chip->running)
+               azx_stop_chip(chip);
+}
+
 /* PCI IDs */
 static const struct pci_device_id azx_ids[] = {
        /* CPT */
@@ -2178,6 +2152,7 @@ static struct pci_driver azx_driver = {
        .id_table = azx_ids,
        .probe = azx_probe,
        .remove = azx_remove,
+       .shutdown = azx_shutdown,
        .driver = {
                .pm = AZX_PM_OPS,
        },
index 3486118354766c307abd9e1f026d638d5a089ad4..d5231f7216a70057cd768f77d7a6a143f73a0f7b 100644 (file)
@@ -17,7 +17,7 @@
 #define __SOUND_HDA_INTEL_H
 
 #include <drm/i915_component.h>
-#include "hda_priv.h"
+#include "hda_controller.h"
 
 struct hda_intel {
        struct azx chip;
index e664307617bd5fe6b5fce5df040328885e94061a..d7cfe7b8c32b10d1e3a64e9ddfc28f5bc1d0d775 100644 (file)
@@ -135,7 +135,7 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_INPUT_JACK
                /* free jack instances manually when clearing/reconfiguring */
                if (!codec->bus->shutdown && jack->jack)
-                       snd_device_free(codec->bus->card, jack->jack);
+                       snd_device_free(codec->card, jack->jack);
 #endif
                for (cb = jack->callback; cb; cb = next) {
                        next = cb->next;
@@ -340,7 +340,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
                        if (!jack->kctl || jack->block_report)
                                continue;
                        state = get_jack_plug_state(jack->pin_sense);
-                       snd_kctl_jack_report(codec->bus->card, jack->kctl, state);
+                       snd_kctl_jack_report(codec->card, jack->kctl, state);
 #ifdef CONFIG_SND_HDA_INPUT_JACK
                        if (jack->jack)
                                snd_jack_report(jack->jack,
@@ -412,11 +412,11 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
        jack->phantom_jack = !!phantom_jack;
 
        state = snd_hda_jack_detect(codec, nid);
-       snd_kctl_jack_report(codec->bus->card, kctl, state);
+       snd_kctl_jack_report(codec->card, kctl, state);
 #ifdef CONFIG_SND_HDA_INPUT_JACK
        if (!phantom_jack) {
                jack->type = get_input_jack_type(codec, nid);
-               err = snd_jack_new(codec->bus->card, name, jack->type,
+               err = snd_jack_new(codec->card, name, jack->type,
                                   &jack->jack);
                if (err < 0)
                        return err;
index 62658f2f8c9f2db94fca481a86da8432858105a0..1d001647fc47bb534be1a2b15bc3aa86812a85fc 100644 (file)
@@ -150,6 +150,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
 #define snd_hda_add_vmaster(codec, name, tlv, slaves, suffix) \
        __snd_hda_add_vmaster(codec, name, tlv, slaves, suffix, true, NULL)
 int snd_hda_codec_reset(struct hda_codec *codec);
+void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec);
 
 enum {
        HDA_VMUTE_OFF,
@@ -272,29 +273,6 @@ int snd_hda_add_imux_item(struct hda_codec *codec,
                          struct hda_input_mux *imux, const char *label,
                          int index, int *type_index_ret);
 
-/*
- * Channel mode helper
- */
-struct hda_channel_mode {
-       int channels;
-       const struct hda_verb *sequence;
-};
-
-int snd_hda_ch_mode_info(struct hda_codec *codec,
-                        struct snd_ctl_elem_info *uinfo,
-                        const struct hda_channel_mode *chmode,
-                        int num_chmodes);
-int snd_hda_ch_mode_get(struct hda_codec *codec,
-                       struct snd_ctl_elem_value *ucontrol,
-                       const struct hda_channel_mode *chmode,
-                       int num_chmodes,
-                       int max_channels);
-int snd_hda_ch_mode_put(struct hda_codec *codec,
-                       struct snd_ctl_elem_value *ucontrol,
-                       const struct hda_channel_mode *chmode,
-                       int num_chmodes,
-                       int *max_channelsp);
-
 /*
  * Multi-channel / digital-out PCM helper
  */
@@ -350,12 +328,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
                                     struct hda_multi_out *mout);
 
-/*
- * generic codec parser
- */
-int snd_hda_parse_generic_codec(struct hda_codec *codec);
-int snd_hda_parse_hdmi_codec(struct hda_codec *codec);
-
 /*
  * generic proc interface
  */
@@ -466,23 +438,6 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
                            const struct snd_hda_pin_quirk *pin_quirk,
                            const struct hda_fixup *fixlist);
 
-
-/*
- * unsolicited event handler
- */
-
-#define HDA_UNSOL_QUEUE_SIZE   64
-
-struct hda_bus_unsolicited {
-       /* ring buffer */
-       u32 queue[HDA_UNSOL_QUEUE_SIZE * 2];
-       unsigned int rp, wp;
-
-       /* workqueue */
-       struct work_struct work;
-       struct hda_bus *bus;
-};
-
 /* helper macros to retrieve pin default-config values */
 #define get_defcfg_connect(cfg) \
        ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
@@ -800,9 +755,13 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
 
 /*
  */
-#define codec_err(codec, fmt, args...) dev_err(&(codec)->dev, fmt, ##args)
-#define codec_warn(codec, fmt, args...) dev_warn(&(codec)->dev, fmt, ##args)
-#define codec_info(codec, fmt, args...) dev_info(&(codec)->dev, fmt, ##args)
-#define codec_dbg(codec, fmt, args...) dev_dbg(&(codec)->dev, fmt, ##args)
+#define codec_err(codec, fmt, args...) \
+       dev_err(hda_codec_dev(codec), fmt, ##args)
+#define codec_warn(codec, fmt, args...) \
+       dev_warn(hda_codec_dev(codec), fmt, ##args)
+#define codec_info(codec, fmt, args...) \
+       dev_info(hda_codec_dev(codec), fmt, ##args)
+#define codec_dbg(codec, fmt, args...) \
+       dev_dbg(hda_codec_dev(codec), fmt, ##args)
 
 #endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
deleted file mode 100644 (file)
index daf4582..0000000
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- *  Common defines for the alsa driver code base for HD Audio.
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
- */
-
-#ifndef __SOUND_HDA_PRIV_H
-#define __SOUND_HDA_PRIV_H
-
-#include <linux/timecounter.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-/*
- * registers
- */
-#define AZX_REG_GCAP                   0x00
-#define   AZX_GCAP_64OK                (1 << 0)   /* 64bit address support */
-#define   AZX_GCAP_NSDO                (3 << 1)   /* # of serial data out signals */
-#define   AZX_GCAP_BSS         (31 << 3)  /* # of bidirectional streams */
-#define   AZX_GCAP_ISS         (15 << 8)  /* # of input streams */
-#define   AZX_GCAP_OSS         (15 << 12) /* # of output streams */
-#define AZX_REG_VMIN                   0x02
-#define AZX_REG_VMAJ                   0x03
-#define AZX_REG_OUTPAY                 0x04
-#define AZX_REG_INPAY                  0x06
-#define AZX_REG_GCTL                   0x08
-#define   AZX_GCTL_RESET       (1 << 0)   /* controller reset */
-#define   AZX_GCTL_FCNTRL      (1 << 1)   /* flush control */
-#define   AZX_GCTL_UNSOL       (1 << 8)   /* accept unsol. response enable */
-#define AZX_REG_WAKEEN                 0x0c
-#define AZX_REG_STATESTS               0x0e
-#define AZX_REG_GSTS                   0x10
-#define   AZX_GSTS_FSTS                (1 << 1)   /* flush status */
-#define AZX_REG_INTCTL                 0x20
-#define AZX_REG_INTSTS                 0x24
-#define AZX_REG_WALLCLK                        0x30    /* 24Mhz source */
-#define AZX_REG_OLD_SSYNC              0x34    /* SSYNC for old ICH */
-#define AZX_REG_SSYNC                  0x38
-#define AZX_REG_CORBLBASE              0x40
-#define AZX_REG_CORBUBASE              0x44
-#define AZX_REG_CORBWP                 0x48
-#define AZX_REG_CORBRP                 0x4a
-#define   AZX_CORBRP_RST       (1 << 15)  /* read pointer reset */
-#define AZX_REG_CORBCTL                        0x4c
-#define   AZX_CORBCTL_RUN      (1 << 1)   /* enable DMA */
-#define   AZX_CORBCTL_CMEIE    (1 << 0)   /* enable memory error irq */
-#define AZX_REG_CORBSTS                        0x4d
-#define   AZX_CORBSTS_CMEI     (1 << 0)   /* memory error indication */
-#define AZX_REG_CORBSIZE               0x4e
-
-#define AZX_REG_RIRBLBASE              0x50
-#define AZX_REG_RIRBUBASE              0x54
-#define AZX_REG_RIRBWP                 0x58
-#define   AZX_RIRBWP_RST       (1 << 15)  /* write pointer reset */
-#define AZX_REG_RINTCNT                        0x5a
-#define AZX_REG_RIRBCTL                        0x5c
-#define   AZX_RBCTL_IRQ_EN     (1 << 0)   /* enable IRQ */
-#define   AZX_RBCTL_DMA_EN     (1 << 1)   /* enable DMA */
-#define   AZX_RBCTL_OVERRUN_EN (1 << 2)   /* enable overrun irq */
-#define AZX_REG_RIRBSTS                        0x5d
-#define   AZX_RBSTS_IRQ                (1 << 0)   /* response irq */
-#define   AZX_RBSTS_OVERRUN    (1 << 2)   /* overrun irq */
-#define AZX_REG_RIRBSIZE               0x5e
-
-#define AZX_REG_IC                     0x60
-#define AZX_REG_IR                     0x64
-#define AZX_REG_IRS                    0x68
-#define   AZX_IRS_VALID                (1<<1)
-#define   AZX_IRS_BUSY         (1<<0)
-
-#define AZX_REG_DPLBASE                        0x70
-#define AZX_REG_DPUBASE                        0x74
-#define   AZX_DPLBASE_ENABLE   0x1     /* Enable position buffer */
-
-/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
-
-/* stream register offsets from stream base */
-#define AZX_REG_SD_CTL                 0x00
-#define AZX_REG_SD_STS                 0x03
-#define AZX_REG_SD_LPIB                        0x04
-#define AZX_REG_SD_CBL                 0x08
-#define AZX_REG_SD_LVI                 0x0c
-#define AZX_REG_SD_FIFOW               0x0e
-#define AZX_REG_SD_FIFOSIZE            0x10
-#define AZX_REG_SD_FORMAT              0x12
-#define AZX_REG_SD_BDLPL               0x18
-#define AZX_REG_SD_BDLPU               0x1c
-
-/* PCI space */
-#define AZX_PCIREG_TCSEL               0x44
-
-/*
- * other constants
- */
-
-/* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE               4096
-#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
-#define AZX_MAX_FRAG           32
-/* max buffer size - no h/w limit, you can increase as you like */
-#define AZX_MAX_BUF_SIZE       (1024*1024*1024)
-
-/* RIRB int mask: overrun[2], response[0] */
-#define RIRB_INT_RESPONSE      0x01
-#define RIRB_INT_OVERRUN       0x04
-#define RIRB_INT_MASK          0x05
-
-/* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS         8
-#define AZX_DEFAULT_CODECS     4
-#define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
-
-/* SD_CTL bits */
-#define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
-#define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
-#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
-#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
-#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
-#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
-#define SD_CTL_STREAM_TAG_SHIFT        20
-
-/* SD_CTL and SD_STS */
-#define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
-#define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
-#define SD_INT_COMPLETE                0x04    /* completion interrupt */
-#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
-                                SD_INT_COMPLETE)
-
-/* SD_STS */
-#define SD_STS_FIFO_READY      0x20    /* FIFO ready */
-
-/* INTCTL and INTSTS */
-#define AZX_INT_ALL_STREAM     0xff       /* all stream interrupts */
-#define AZX_INT_CTRL_EN        0x40000000 /* controller interrupt enable bit */
-#define AZX_INT_GLOBAL_EN      0x80000000 /* global interrupt enable bit */
-
-/* below are so far hardcoded - should read registers in future */
-#define AZX_MAX_CORB_ENTRIES   256
-#define AZX_MAX_RIRB_ENTRIES   256
-
-/* driver quirks (capabilities) */
-/* bits 0-7 are used for indicating driver type */
-#define AZX_DCAPS_NO_TCSEL     (1 << 8)        /* No Intel TCSEL bit */
-#define AZX_DCAPS_NO_MSI       (1 << 9)        /* No MSI support */
-#define AZX_DCAPS_SNOOP_MASK   (3 << 10)       /* snoop type mask */
-#define AZX_DCAPS_SNOOP_OFF    (1 << 12)       /* snoop default off */
-#define AZX_DCAPS_RIRB_DELAY   (1 << 13)       /* Long delay in read loop */
-#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14)     /* Put a delay before read */
-#define AZX_DCAPS_CTX_WORKAROUND (1 << 15)     /* X-Fi workaround */
-#define AZX_DCAPS_POSFIX_LPIB  (1 << 16)       /* Use LPIB as default */
-#define AZX_DCAPS_POSFIX_VIA   (1 << 17)       /* Use VIACOMBO as default */
-#define AZX_DCAPS_NO_64BIT     (1 << 18)       /* No 64bit address */
-#define AZX_DCAPS_SYNC_WRITE   (1 << 19)       /* sync each cmd write */
-#define AZX_DCAPS_OLD_SSYNC    (1 << 20)       /* Old SSYNC reg for ICH */
-#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21)   /* no buffer size alignment */
-/* 22 unused */
-#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)   /* BDLE in 4k boundary */
-#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24)     /* Assign devices in reverse order */
-#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)  /* Take LPIB as delay */
-#define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
-#define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 powerwell support */
-#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)  /* CORBRP clears itself after reset */
-#define AZX_DCAPS_NO_MSI64      (1 << 29)      /* Stick to 32-bit MSIs */
-#define AZX_DCAPS_SEPARATE_STREAM_TAG  (1 << 30) /* capture and playback use separate stream tag */
-
-enum {
-       AZX_SNOOP_TYPE_NONE ,
-       AZX_SNOOP_TYPE_SCH,
-       AZX_SNOOP_TYPE_ATI,
-       AZX_SNOOP_TYPE_NVIDIA,
-};
-
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
-
-struct azx_dev {
-       struct snd_dma_buffer bdl; /* BDL buffer */
-       u32 *posbuf;            /* position buffer pointer */
-
-       unsigned int bufsize;   /* size of the play buffer in bytes */
-       unsigned int period_bytes; /* size of the period in bytes */
-       unsigned int frags;     /* number for period in the play buffer */
-       unsigned int fifo_size; /* FIFO size */
-       unsigned long start_wallclk;    /* start + minimum wallclk */
-       unsigned long period_wallclk;   /* wallclk for period */
-
-       void __iomem *sd_addr;  /* stream descriptor pointer */
-
-       u32 sd_int_sta_mask;    /* stream int status mask */
-
-       /* pcm support */
-       struct snd_pcm_substream *substream;    /* assigned substream,
-                                                * set in PCM open
-                                                */
-       unsigned int format_val;        /* format value to be set in the
-                                        * controller and the codec
-                                        */
-       unsigned char stream_tag;       /* assigned stream */
-       unsigned char index;            /* stream index */
-       int assigned_key;               /* last device# key assigned to */
-
-       unsigned int opened:1;
-       unsigned int running:1;
-       unsigned int irq_pending:1;
-       unsigned int prepared:1;
-       unsigned int locked:1;
-       /*
-        * For VIA:
-        *  A flag to ensure DMA position is 0
-        *  when link position is not greater than FIFO size
-        */
-       unsigned int insufficient:1;
-       unsigned int wc_marked:1;
-       unsigned int no_period_wakeup:1;
-
-       struct timecounter  azx_tc;
-       struct cyclecounter azx_cc;
-
-       int delay_negative_threshold;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-       /* Allows dsp load to have sole access to the playback stream. */
-       struct mutex dsp_mutex;
-#endif
-};
-
-/* CORB/RIRB */
-struct azx_rb {
-       u32 *buf;               /* CORB/RIRB buffer
-                                * Each CORB entry is 4byte, RIRB is 8byte
-                                */
-       dma_addr_t addr;        /* physical address of CORB/RIRB buffer */
-       /* for RIRB */
-       unsigned short rp, wp;  /* read/write pointers */
-       int cmds[AZX_MAX_CODECS];       /* number of pending requests */
-       u32 res[AZX_MAX_CODECS];        /* last read value */
-};
-
-struct azx;
-
-/* Functions to read/write to hda registers. */
-struct hda_controller_ops {
-       /* Register Access */
-       void (*reg_writel)(u32 value, u32 __iomem *addr);
-       u32 (*reg_readl)(u32 __iomem *addr);
-       void (*reg_writew)(u16 value, u16 __iomem *addr);
-       u16 (*reg_readw)(u16 __iomem *addr);
-       void (*reg_writeb)(u8 value, u8 __iomem *addr);
-       u8 (*reg_readb)(u8 __iomem *addr);
-       /* Disable msi if supported, PCI only */
-       int (*disable_msi_reset_irq)(struct azx *);
-       /* Allocation ops */
-       int (*dma_alloc_pages)(struct azx *chip,
-                              int type,
-                              size_t size,
-                              struct snd_dma_buffer *buf);
-       void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf);
-       int (*substream_alloc_pages)(struct azx *chip,
-                                    struct snd_pcm_substream *substream,
-                                    size_t size);
-       int (*substream_free_pages)(struct azx *chip,
-                                   struct snd_pcm_substream *substream);
-       void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
-                                struct vm_area_struct *area);
-       /* Check if current position is acceptable */
-       int (*position_check)(struct azx *chip, struct azx_dev *azx_dev);
-};
-
-struct azx_pcm {
-       struct azx *chip;
-       struct snd_pcm *pcm;
-       struct hda_codec *codec;
-       struct hda_pcm_stream *hinfo[2];
-       struct list_head list;
-};
-
-typedef unsigned int (*azx_get_pos_callback_t)(struct azx *, struct azx_dev *);
-typedef int (*azx_get_delay_callback_t)(struct azx *, struct azx_dev *, unsigned int pos);
-
-struct azx {
-       struct snd_card *card;
-       struct pci_dev *pci;
-       int dev_index;
-
-       /* chip type specific */
-       int driver_type;
-       unsigned int driver_caps;
-       int playback_streams;
-       int playback_index_offset;
-       int capture_streams;
-       int capture_index_offset;
-       int num_streams;
-       const int *jackpoll_ms; /* per-card jack poll interval */
-
-       /* Register interaction. */
-       const struct hda_controller_ops *ops;
-
-       /* position adjustment callbacks */
-       azx_get_pos_callback_t get_position[2];
-       azx_get_delay_callback_t get_delay[2];
-
-       /* pci resources */
-       unsigned long addr;
-       void __iomem *remap_addr;
-       int irq;
-
-       /* locks */
-       spinlock_t reg_lock;
-       struct mutex open_mutex; /* Prevents concurrent open/close operations */
-
-       /* streams (x num_streams) */
-       struct azx_dev *azx_dev;
-
-       /* PCM */
-       struct list_head pcm_list; /* azx_pcm list */
-
-       /* HD codec */
-       unsigned short codec_mask;
-       int  codec_probe_mask; /* copied from probe_mask option */
-       struct hda_bus *bus;
-       unsigned int beep_mode;
-
-       /* CORB/RIRB */
-       struct azx_rb corb;
-       struct azx_rb rirb;
-
-       /* CORB/RIRB and position buffers */
-       struct snd_dma_buffer rb;
-       struct snd_dma_buffer posbuf;
-
-#ifdef CONFIG_SND_HDA_PATCH_LOADER
-       const struct firmware *fw;
-#endif
-
-       /* flags */
-       const int *bdl_pos_adj;
-       int poll_count;
-       unsigned int running:1;
-       unsigned int initialized:1;
-       unsigned int single_cmd:1;
-       unsigned int polling_mode:1;
-       unsigned int msi:1;
-       unsigned int probing:1; /* codec probing phase */
-       unsigned int snoop:1;
-       unsigned int align_buffer_size:1;
-       unsigned int region_requested:1;
-       unsigned int disabled:1; /* disabled by VGA-switcher */
-
-       /* for debugging */
-       unsigned int last_cmd[AZX_MAX_CODECS];
-
-       /* reboot notifier (for mysterious hangup problem at power-down) */
-       struct notifier_block reboot_notifier;
-
-#ifdef CONFIG_SND_HDA_DSP_LOADER
-       struct azx_dev saved_azx_dev;
-#endif
-};
-
-#ifdef CONFIG_X86
-#define azx_snoop(chip)                ((chip)->snoop)
-#else
-#define azx_snoop(chip)                true
-#endif
-
-/*
- * macros for easy use
- */
-
-#define azx_writel(chip, reg, value) \
-       ((chip)->ops->reg_writel(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readl(chip, reg) \
-       ((chip)->ops->reg_readl((chip)->remap_addr + AZX_REG_##reg))
-#define azx_writew(chip, reg, value) \
-       ((chip)->ops->reg_writew(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readw(chip, reg) \
-       ((chip)->ops->reg_readw((chip)->remap_addr + AZX_REG_##reg))
-#define azx_writeb(chip, reg, value) \
-       ((chip)->ops->reg_writeb(value, (chip)->remap_addr + AZX_REG_##reg))
-#define azx_readb(chip, reg) \
-       ((chip)->ops->reg_readb((chip)->remap_addr + AZX_REG_##reg))
-
-#define azx_sd_writel(chip, dev, reg, value) \
-       ((chip)->ops->reg_writel(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readl(chip, dev, reg) \
-       ((chip)->ops->reg_readl((dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_writew(chip, dev, reg, value) \
-       ((chip)->ops->reg_writew(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readw(chip, dev, reg) \
-       ((chip)->ops->reg_readw((dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_writeb(chip, dev, reg, value) \
-       ((chip)->ops->reg_writeb(value, (dev)->sd_addr + AZX_REG_##reg))
-#define azx_sd_readb(chip, dev, reg) \
-       ((chip)->ops->reg_readb((dev)->sd_addr + AZX_REG_##reg))
-
-#endif /* __SOUND_HDA_PRIV_H */
index 05e19f78b4cb8689ff8ac1b0b4f699bdbf5759da..dacfe74a2a1fefc432fb36f58f5e645f10f04057 100644 (file)
@@ -99,10 +99,10 @@ static void print_nid_array(struct snd_info_buffer *buffer,
 static void print_nid_pcms(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid)
 {
-       int pcm, type;
+       int type;
        struct hda_pcm *cpcm;
-       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
-               cpcm = &codec->pcm_info[pcm];
+
+       list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
                for (type = 0; type < 2; type++) {
                        if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
                                continue;
@@ -861,7 +861,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec)
        int err;
 
        snprintf(name, sizeof(name), "codec#%d", codec->addr);
-       err = snd_card_proc_new(codec->bus->card, name, &entry);
+       err = snd_card_proc_new(codec->card, name, &entry);
        if (err < 0)
                return err;
 
index ccc962a1699f1b160dc3ad074496d003e173919a..e13c75d6784794a5017838990b77e3b3d47c0f88 100644 (file)
@@ -149,7 +149,7 @@ static int reconfig_codec(struct hda_codec *codec)
        err = snd_hda_codec_build_controls(codec);
        if (err < 0)
                goto error;
-       err = snd_card_register(codec->bus->card);
+       err = snd_card_register(codec->card);
  error:
        snd_hda_power_down(codec);
        return err;
index 375e94f4cf5265ba19378f96998658a5e4fed91c..2e4fd5c56d3b9655cdc93dee94694a851f4c689b 100644 (file)
@@ -37,7 +37,6 @@
 
 #include "hda_codec.h"
 #include "hda_controller.h"
-#include "hda_priv.h"
 
 /* Defines for Nvidia Tegra HDA support */
 #define HDA_BAR0           0x8000
@@ -82,7 +81,7 @@ module_param(power_save, bint, 0644);
 MODULE_PARM_DESC(power_save,
                 "Automatic power-saving timeout (in seconds, 0 = disable).");
 #else
-static int power_save = 0;
+#define power_save     0
 #endif
 
 /*
@@ -250,14 +249,9 @@ static int hda_tegra_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip = card->private_data;
-       struct azx_pcm *p;
        struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       list_for_each_entry(p, &chip->pcm_list, list)
-               snd_pcm_suspend_all(p->pcm);
-       if (chip->initialized)
-               snd_hda_suspend(chip->bus);
 
        azx_stop_chip(chip);
        azx_enter_link_reset(chip);
@@ -278,7 +272,6 @@ static int hda_tegra_resume(struct device *dev)
 
        azx_init_chip(chip, 1);
 
-       snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 
        return 0;
@@ -297,8 +290,6 @@ static int hda_tegra_dev_free(struct snd_device *device)
        int i;
        struct azx *chip = device->device_data;
 
-       azx_notifier_unregister(chip);
-
        if (chip->initialized) {
                for (i = 0; i < chip->num_streams; i++)
                        azx_stream_stop(chip, &chip->azx_dev[i]);
@@ -344,17 +335,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
        return 0;
 }
 
-/*
- * The codecs were powered up in snd_hda_codec_new().
- * Now all initialization done, so turn them down if possible
- */
-static void power_down_all_codecs(struct azx *chip)
-{
-       struct hda_codec *codec;
-       list_for_each_entry(codec, &chip->bus->codec_list, list)
-               snd_hda_power_down(codec);
-}
-
 static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
 {
        struct snd_card *card = chip->card;
@@ -503,21 +483,15 @@ static int hda_tegra_probe(struct platform_device *pdev)
                goto out_free;
 
        /* create codec instances */
-       err = azx_codec_create(chip, NULL, 0, &power_save);
+       err = azx_bus_create(chip, NULL);
        if (err < 0)
                goto out_free;
 
-       err = azx_codec_configure(chip);
+       err = azx_probe_codecs(chip, 0);
        if (err < 0)
                goto out_free;
 
-       /* create PCM streams */
-       err = snd_hda_build_pcms(chip->bus);
-       if (err < 0)
-               goto out_free;
-
-       /* create mixer controls */
-       err = azx_mixer_create(chip);
+       err = azx_codec_configure(chip);
        if (err < 0)
                goto out_free;
 
@@ -526,8 +500,7 @@ static int hda_tegra_probe(struct platform_device *pdev)
                goto out_free;
 
        chip->running = 1;
-       power_down_all_codecs(chip);
-       azx_notifier_register(chip);
+       snd_hda_set_power_save(chip->bus, power_save * 1000);
 
        return 0;
 
@@ -541,6 +514,18 @@ static int hda_tegra_remove(struct platform_device *pdev)
        return snd_card_free(dev_get_drvdata(&pdev->dev));
 }
 
+static void hda_tegra_shutdown(struct platform_device *pdev)
+{
+       struct snd_card *card = dev_get_drvdata(&pdev->dev);
+       struct azx *chip;
+
+       if (!card)
+               return;
+       chip = card->private_data;
+       if (chip && chip->running)
+               azx_stop_chip(chip);
+}
+
 static struct platform_driver tegra_platform_hda = {
        .driver = {
                .name = "tegra-hda",
@@ -549,6 +534,7 @@ static struct platform_driver tegra_platform_hda = {
        },
        .probe = hda_tegra_probe,
        .remove = hda_tegra_remove,
+       .shutdown = hda_tegra_shutdown,
 };
 module_platform_driver(tegra_platform_hda);
 
index 3a1c63161eb129d71a02203ce9fe3a3b24ec6df4..7fedfa8624197067ac9218a82d6c70b1e5c0126f 100644 (file)
@@ -23,7 +23,7 @@ DECLARE_EVENT_CLASS(hda_cmd,
        ),
 
        TP_fast_assign(
-               __entry->card = (codec)->bus->card->number;
+               __entry->card = (codec)->card->number;
                __entry->addr = (codec)->addr;
                __entry->val = (val);
        ),
@@ -71,7 +71,7 @@ DECLARE_EVENT_CLASS(hda_power,
        ),
 
        TP_fast_assign(
-               __entry->card = (codec)->bus->card->number;
+               __entry->card = (codec)->card->number;
                __entry->addr = (codec)->addr;
        ),
 
@@ -87,30 +87,6 @@ DEFINE_EVENT(hda_power, hda_power_up,
        TP_PROTO(struct hda_codec *codec),
        TP_ARGS(codec)
 );
-
-TRACE_EVENT(hda_power_count,
-       TP_PROTO(struct hda_codec *codec),
-       TP_ARGS(codec),
-       TP_STRUCT__entry(
-               __field( unsigned int, card )
-               __field( unsigned int, addr )
-               __field( int, power_count )
-               __field( int, power_on )
-               __field( int, power_transition )
-       ),
-
-       TP_fast_assign(
-               __entry->card = (codec)->bus->card->number;
-               __entry->addr = (codec)->addr;
-               __entry->power_count = (codec)->power_count;
-               __entry->power_on = (codec)->power_on;
-               __entry->power_transition = (codec)->power_transition;
-       ),
-
-       TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d",
-                 __entry->card, __entry->addr, __entry->power_count,
-                 __entry->power_on, __entry->power_transition)
-);
 #endif /* CONFIG_PM */
 
 TRACE_EVENT(hda_unsol_event,
index d285904cdb64a0e88a51e5ee107a013500b25a0f..af4c7be86c27b85db494a026aa85f3824f9a538b 100644 (file)
@@ -1194,20 +1194,8 @@ MODULE_ALIAS("snd-hda-codec-id:11d4*");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
 
-static struct hda_codec_preset_list analog_list = {
+static struct hda_codec_driver analog_driver = {
        .preset = snd_hda_preset_analog,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_analog_init(void)
-{
-       return snd_hda_add_codec_preset(&analog_list);
-}
-
-static void __exit patch_analog_exit(void)
-{
-       snd_hda_delete_codec_preset(&analog_list);
-}
-
-module_init(patch_analog_init)
-module_exit(patch_analog_exit)
+module_hda_codec_driver(analog_driver);
index 5e65999e0d8e6a410061fe87fd287bd695b7305e..447302695195723b5e95ad7a1c6565e5b7e16a81 100644 (file)
@@ -98,20 +98,8 @@ MODULE_ALIAS("snd-hda-codec-id:1102000d");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
 
-static struct hda_codec_preset_list ca0110_list = {
+static struct hda_codec_driver ca0110_driver = {
        .preset = snd_hda_preset_ca0110,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_ca0110_init(void)
-{
-       return snd_hda_add_codec_preset(&ca0110_list);
-}
-
-static void __exit patch_ca0110_exit(void)
-{
-       snd_hda_delete_codec_preset(&ca0110_list);
-}
-
-module_init(patch_ca0110_init)
-module_exit(patch_ca0110_exit)
+module_hda_codec_driver(ca0110_driver);
index e0383eea988024b77116b96e07d7528fb3bd60e7..72d20652df504ba4cd9a2711bf918bc365608969 100644 (file)
@@ -719,7 +719,6 @@ struct ca0132_spec {
        unsigned int num_inputs;
        hda_nid_t shared_mic_nid;
        hda_nid_t shared_out_nid;
-       struct hda_pcm pcm_rec[5]; /* PCM information */
 
        /* chip access */
        struct mutex chipio_mutex; /* chip access mutex */
@@ -4036,12 +4035,11 @@ static struct hda_pcm_stream ca0132_pcm_digital_capture = {
 static int ca0132_build_pcms(struct hda_codec *codec)
 {
        struct ca0132_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
+       struct hda_pcm *info;
 
-       codec->pcm_info = info;
-       codec->num_pcms = 0;
-
-       info->name = "CA0132 Analog";
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
+       if (!info)
+               return -ENOMEM;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
@@ -4049,27 +4047,27 @@ static int ca0132_build_pcms(struct hda_codec *codec)
        info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
-       codec->num_pcms++;
 
-       info++;
-       info->name = "CA0132 Analog Mic-In2";
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
+       if (!info)
+               return -ENOMEM;
        info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
-       codec->num_pcms++;
 
-       info++;
-       info->name = "CA0132 What U Hear";
+       info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear");
+       if (!info)
+               return -ENOMEM;
        info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
-       codec->num_pcms++;
 
        if (!spec->dig_out && !spec->dig_in)
                return 0;
 
-       info++;
-       info->name = "CA0132 Digital";
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
+       if (!info)
+               return -ENOMEM;
        info->pcm_type = HDA_PCM_TYPE_SPDIF;
        if (spec->dig_out) {
                info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
@@ -4081,7 +4079,6 @@ static int ca0132_build_pcms(struct hda_codec *codec)
                        ca0132_pcm_digital_capture;
                info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
        }
-       codec->num_pcms++;
 
        return 0;
 }
@@ -4352,7 +4349,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
        const struct dsp_image_seg *dsp_os_image;
        const struct firmware *fw_entry;
 
-       if (request_firmware(&fw_entry, EFX_FILE, codec->bus->card->dev) != 0)
+       if (request_firmware(&fw_entry, EFX_FILE, codec->card->dev) != 0)
                return false;
 
        dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
@@ -4413,8 +4410,7 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
         * state machine run.
         */
        cancel_delayed_work_sync(&spec->unsol_hp_work);
-       queue_delayed_work(codec->bus->workq, &spec->unsol_hp_work,
-                          msecs_to_jiffies(500));
+       schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
        cb->tbl->block_report = 1;
 }
 
@@ -4702,20 +4698,8 @@ MODULE_ALIAS("snd-hda-codec-id:11020011");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Creative Sound Core3D codec");
 
-static struct hda_codec_preset_list ca0132_list = {
+static struct hda_codec_driver ca0132_driver = {
        .preset = snd_hda_preset_ca0132,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_ca0132_init(void)
-{
-       return snd_hda_add_codec_preset(&ca0132_list);
-}
-
-static void __exit patch_ca0132_exit(void)
-{
-       snd_hda_delete_codec_preset(&ca0132_list);
-}
-
-module_init(patch_ca0132_init)
-module_exit(patch_ca0132_exit)
+module_hda_codec_driver(ca0132_driver);
index dd2b3d92071f698f41a75d2d7b7877eb6b357c00..50e9dd67557973a0e07e8caded74d37bf78bb0d2 100644 (file)
@@ -1221,20 +1221,8 @@ MODULE_ALIAS("snd-hda-codec-id:10134213");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
 
-static struct hda_codec_preset_list cirrus_list = {
+static struct hda_codec_driver cirrus_driver = {
        .preset = snd_hda_preset_cirrus,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_cirrus_init(void)
-{
-       return snd_hda_add_codec_preset(&cirrus_list);
-}
-
-static void __exit patch_cirrus_exit(void)
-{
-       snd_hda_delete_codec_preset(&cirrus_list);
-}
-
-module_init(patch_cirrus_init)
-module_exit(patch_cirrus_exit)
+module_hda_codec_driver(cirrus_driver);
index c895a8f211922415b1498a2092772149d9ab13c7..617d9012e78abe30a0ac4e705e50086d705bb80b 100644 (file)
@@ -137,20 +137,8 @@ MODULE_ALIAS("snd-hda-codec-id:434d4980");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("C-Media HD-audio codec");
 
-static struct hda_codec_preset_list cmedia_list = {
+static struct hda_codec_driver cmedia_driver = {
        .preset = snd_hda_preset_cmedia,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_cmedia_init(void)
-{
-       return snd_hda_add_codec_preset(&cmedia_list);
-}
-
-static void __exit patch_cmedia_exit(void)
-{
-       snd_hda_delete_codec_preset(&cmedia_list);
-}
-
-module_init(patch_cmedia_init)
-module_exit(patch_cmedia_exit)
+module_hda_codec_driver(cmedia_driver);
index da67ea8645a6e8462f23b8f8b1e96044e66812f7..5aa466a13e430cc962a3c8315b715af70640a765 100644 (file)
@@ -1018,20 +1018,8 @@ MODULE_ALIAS("snd-hda-codec-id:14f151d7");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
 
-static struct hda_codec_preset_list conexant_list = {
+static struct hda_codec_driver conexant_driver = {
        .preset = snd_hda_preset_conexant,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_conexant_init(void)
-{
-       return snd_hda_add_codec_preset(&conexant_list);
-}
-
-static void __exit patch_conexant_exit(void)
-{
-       snd_hda_delete_codec_preset(&conexant_list);
-}
-
-module_init(patch_conexant_init)
-module_exit(patch_conexant_exit)
+module_hda_codec_driver(conexant_driver);
index b422e406a9cb3ba284772d4fbd6d42854de40b95..7e9ff7b16e5658d5fb3037c0201ee69b9268890d 100644 (file)
@@ -86,7 +86,6 @@ struct hdmi_spec_per_pin {
        bool non_pcm;
        bool chmap_set;         /* channel-map override by ALSA API? */
        unsigned char chmap[8]; /* ALSA API channel-map */
-       char pcm_name[8];       /* filled in build_pcm callbacks */
 #ifdef CONFIG_PROC_FS
        struct snd_info_entry *proc_entry;
 #endif
@@ -132,7 +131,7 @@ struct hdmi_spec {
 
        int num_pins;
        struct snd_array pins; /* struct hdmi_spec_per_pin */
-       struct snd_array pcm_rec; /* struct hda_pcm */
+       struct hda_pcm *pcm_rec[16];
        unsigned int channels_max; /* max over all cvts */
 
        struct hdmi_eld temp_eld;
@@ -355,8 +354,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
        ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
 #define get_cvt(spec, idx) \
        ((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
-#define get_pcm_rec(spec, idx) \
-       ((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
+#define get_pcm_rec(spec, idx) ((spec)->pcm_rec[idx])
 
 static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
 {
@@ -579,7 +577,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
        int err;
 
        snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
-       err = snd_card_proc_new(codec->bus->card, name, &entry);
+       err = snd_card_proc_new(codec->card, name, &entry);
        if (err < 0)
                return err;
 
@@ -594,7 +592,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
 static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
 {
        if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) {
-               snd_device_free(per_pin->codec->bus->card, per_pin->proc_entry);
+               snd_device_free(per_pin->codec->card, per_pin->proc_entry);
                per_pin->proc_entry = NULL;
        }
 }
@@ -1578,9 +1576,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
                        update_eld = true;
                }
                else if (repoll) {
-                       queue_delayed_work(codec->bus->workq,
-                                          &per_pin->work,
-                                          msecs_to_jiffies(300));
+                       schedule_delayed_work(&per_pin->work,
+                                             msecs_to_jiffies(300));
                        goto unlock;
                }
        }
@@ -1624,7 +1621,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
        }
 
        if (eld_changed)
-               snd_ctl_notify(codec->bus->card,
+               snd_ctl_notify(codec->card,
                               SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
                               &per_pin->eld_ctl->id);
  unlock:
@@ -2056,11 +2053,10 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
                struct hdmi_spec_per_pin *per_pin;
 
                per_pin = get_pin(spec, pin_idx);
-               sprintf(per_pin->pcm_name, "HDMI %d", pin_idx);
-               info = snd_array_new(&spec->pcm_rec);
+               info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
                if (!info)
                        return -ENOMEM;
-               info->name = per_pin->pcm_name;
+               spec->pcm_rec[pin_idx] = info;
                info->pcm_type = HDA_PCM_TYPE_HDMI;
                info->own_chmap = true;
 
@@ -2070,9 +2066,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
                /* other pstr fields are set in open */
        }
 
-       codec->num_pcms = spec->num_pins;
-       codec->pcm_info = spec->pcm_rec.list;
-
        return 0;
 }
 
@@ -2125,13 +2118,15 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 
        /* add channel maps */
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hda_pcm *pcm;
                struct snd_pcm_chmap *chmap;
                struct snd_kcontrol *kctl;
                int i;
 
-               if (!codec->pcm_info[pin_idx].pcm)
+               pcm = spec->pcm_rec[pin_idx];
+               if (!pcm || !pcm->pcm)
                        break;
-               err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm,
+               err = snd_pcm_add_chmap_ctls(pcm->pcm,
                                             SNDRV_PCM_STREAM_PLAYBACK,
                                             NULL, 0, pin_idx, &chmap);
                if (err < 0)
@@ -2186,14 +2181,12 @@ static void hdmi_array_init(struct hdmi_spec *spec, int nums)
 {
        snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
        snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
-       snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums);
 }
 
 static void hdmi_array_free(struct hdmi_spec *spec)
 {
        snd_array_free(&spec->pins);
        snd_array_free(&spec->cvts);
-       snd_array_free(&spec->pcm_rec);
 }
 
 static void generic_hdmi_free(struct hda_codec *codec)
@@ -2204,11 +2197,10 @@ static void generic_hdmi_free(struct hda_codec *codec)
        for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
                struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 
-               cancel_delayed_work(&per_pin->work);
+               cancel_delayed_work_sync(&per_pin->work);
                eld_proc_free(per_pin);
        }
 
-       flush_workqueue(codec->bus->workq);
        hdmi_array_free(spec);
        kfree(spec);
 }
@@ -2381,11 +2373,10 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
        chans = get_wcaps(codec, per_cvt->cvt_nid);
        chans = get_wcaps_channels(chans);
 
-       info = snd_array_new(&spec->pcm_rec);
+       info = snd_hda_codec_pcm_new(codec, "HDMI 0");
        if (!info)
                return -ENOMEM;
-       info->name = get_pin(spec, 0)->pcm_name;
-       sprintf(info->name, "HDMI 0");
+       spec->pcm_rec[0] = info;
        info->pcm_type = HDA_PCM_TYPE_HDMI;
        pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
        *pstr = spec->pcm_playback;
@@ -2393,9 +2384,6 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
        if (pstr->channels_max <= 2 && chans && chans <= 16)
                pstr->channels_max = chans;
 
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
        return 0;
 }
 
@@ -3300,15 +3288,6 @@ static int patch_via_hdmi(struct hda_codec *codec)
        return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
 }
 
-/*
- * called from hda_codec.c for generic HDMI support
- */
-int snd_hda_parse_hdmi_codec(struct hda_codec *codec)
-{
-       return patch_generic_hdmi(codec);
-}
-EXPORT_SYMBOL_GPL(snd_hda_parse_hdmi_codec);
-
 /*
  * patch entries
  */
@@ -3373,6 +3352,8 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x80862882, .name = "Valleyview2 HDMI",        .patch = patch_generic_hdmi },
 { .id = 0x80862883, .name = "Braswell HDMI",   .patch = patch_generic_hdmi },
 { .id = 0x808629fb, .name = "Crestline HDMI",  .patch = patch_generic_hdmi },
+/* special ID for generic HDMI */
+{ .id = HDA_CODEC_ID_GENERIC_HDMI, .patch = patch_generic_hdmi },
 {} /* terminator */
 };
 
@@ -3442,20 +3423,8 @@ MODULE_ALIAS("snd-hda-codec-intelhdmi");
 MODULE_ALIAS("snd-hda-codec-nvhdmi");
 MODULE_ALIAS("snd-hda-codec-atihdmi");
 
-static struct hda_codec_preset_list intel_list = {
+static struct hda_codec_driver hdmi_driver = {
        .preset = snd_hda_preset_hdmi,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_hdmi_init(void)
-{
-       return snd_hda_add_codec_preset(&intel_list);
-}
-
-static void __exit patch_hdmi_exit(void)
-{
-       snd_hda_delete_codec_preset(&intel_list);
-}
-
-module_init(patch_hdmi_init)
-module_exit(patch_hdmi_exit)
+module_hda_codec_driver(hdmi_driver);
index 526398a4a4428da11d5792c9c7f2a299cac9bd43..124eacf67fc4dc9748ba0593103b4c9d6f4a5b3b 100644 (file)
@@ -2602,53 +2602,12 @@ static int patch_alc268(struct hda_codec *codec)
  * ALC269
  */
 
-static int playback_pcm_open(struct hda_pcm_stream *hinfo,
-                            struct hda_codec *codec,
-                            struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
-                                            hinfo);
-}
-
-static int 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 hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
-                                               stream_tag, format, substream);
-}
-
-static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                               struct hda_codec *codec,
-                               struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
 static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 8,
        .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-       /* NID is set in alc_build_pcms */
-       .ops = {
-               .open = playback_pcm_open,
-               .prepare = playback_pcm_prepare,
-               .cleanup = playback_pcm_cleanup
-       },
 };
 
 static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
        .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-       /* NID is set in alc_build_pcms */
 };
 
 /* different alc269-variants */
@@ -5850,7 +5809,7 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
 {
        if (action == HDA_FIXUP_ACT_BUILD) {
                struct alc_spec *spec = codec->spec;
-               spec->gen.pcm_rec[0].stream[0].chmap = asus_pcm_2_1_chmaps;
+               spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
        }
 }
 
@@ -6521,20 +6480,8 @@ MODULE_ALIAS("snd-hda-codec-id:10ec*");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek HD-audio codec");
 
-static struct hda_codec_preset_list realtek_list = {
+static struct hda_codec_driver realtek_driver = {
        .preset = snd_hda_preset_realtek,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_realtek_init(void)
-{
-       return snd_hda_add_codec_preset(&realtek_list);
-}
-
-static void __exit patch_realtek_exit(void)
-{
-       snd_hda_delete_codec_preset(&realtek_list);
-}
-
-module_init(patch_realtek_init)
-module_exit(patch_realtek_exit)
+module_hda_codec_driver(realtek_driver);
index 3208ad69583ee5564272d16ce2fd97185351a53c..df243134baa883bf5d61f7a2ec58fcd76383ef93 100644 (file)
@@ -83,7 +83,6 @@
 
 struct si3054_spec {
        unsigned international;
-       struct hda_pcm pcm;
 };
 
 
@@ -199,11 +198,11 @@ static const struct hda_pcm_stream si3054_pcm = {
 
 static int si3054_build_pcms(struct hda_codec *codec)
 {
-       struct si3054_spec *spec = codec->spec;
-       struct hda_pcm *info = &spec->pcm;
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-       info->name = "Si3054 Modem";
+       struct hda_pcm *info;
+
+       info = snd_hda_codec_pcm_new(codec, "Si3054 Modem");
+       if (!info)
+               return -ENOMEM;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
        info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->mfg;
@@ -319,20 +318,8 @@ MODULE_ALIAS("snd-hda-codec-id:18540018");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
 
-static struct hda_codec_preset_list si3054_list = {
+static struct hda_codec_driver si3054_driver = {
        .preset = snd_hda_preset_si3054,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_si3054_init(void)
-{
-       return snd_hda_add_codec_preset(&si3054_list);
-}
-
-static void __exit patch_si3054_exit(void)
-{
-       snd_hda_delete_codec_preset(&si3054_list);
-}
-
-module_init(patch_si3054_init)
-module_exit(patch_si3054_exit)
+module_hda_codec_driver(si3054_driver);
index 87eff3173ce924ae89596068b5bf8dcd38e7482e..5b7c173adcb8c4d9c8ee9f0ad3878ba4e33c8f81 100644 (file)
@@ -2132,8 +2132,10 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
 
        if (action == HDA_FIXUP_ACT_PRE_PROBE) {
                spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
+#ifdef CONFIG_PM
                /* resetting controller clears GPIO, so we need to keep on */
-               codec->bus->power_keep_link_on = 1;
+               codec->d3_stop_clk = 0;
+#endif
        }
 }
 
@@ -4223,6 +4225,12 @@ static int stac_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
+       if (spec->vref_mute_led_nid) {
+               err = snd_hda_gen_fix_pin_power(codec, spec->vref_mute_led_nid);
+               if (err < 0)
+                       return err;
+       }
+
        /* setup analog beep controls */
        if (spec->anabeep_nid > 0) {
                err = stac_auto_create_beep_ctls(codec,
@@ -4392,6 +4400,7 @@ static const struct hda_codec_ops stac_patch_ops = {
 #ifdef CONFIG_PM
        .suspend = stac_suspend,
 #endif
+       .stream_pm = snd_hda_gen_stream_pm,
        .reboot_notify = stac_shutup,
 };
 
@@ -4485,6 +4494,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
                return err;
 
        spec = codec->spec;
+       codec->power_save_node = 1;
        spec->linear_tone_beep = 0;
        spec->gen.mixer_nid = 0x1d;
        spec->have_spdif_mux = 1;
@@ -4590,6 +4600,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        codec->epss = 0; /* longer delay needed for D3 */
 
        spec = codec->spec;
+       codec->power_save_node = 1;
        spec->linear_tone_beep = 0;
        spec->gen.own_eapd_ctl = 1;
        spec->gen.power_down_unused = 1;
@@ -4639,6 +4650,7 @@ static int patch_stac92hd95(struct hda_codec *codec)
        codec->epss = 0; /* longer delay needed for D3 */
 
        spec = codec->spec;
+       codec->power_save_node = 1;
        spec->linear_tone_beep = 0;
        spec->gen.own_eapd_ctl = 1;
        spec->gen.power_down_unused = 1;
@@ -4680,6 +4692,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
                return err;
 
        spec = codec->spec;
+       codec->power_save_node = 1;
        spec->linear_tone_beep = 0;
        spec->gen.own_eapd_ctl = 1;
        spec->gen.power_down_unused = 1;
@@ -5091,20 +5104,8 @@ MODULE_ALIAS("snd-hda-codec-id:111d*");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
 
-static struct hda_codec_preset_list sigmatel_list = {
+static struct hda_codec_driver sigmatel_driver = {
        .preset = snd_hda_preset_sigmatel,
-       .owner = THIS_MODULE,
 };
 
-static int __init patch_sigmatel_init(void)
-{
-       return snd_hda_add_codec_preset(&sigmatel_list);
-}
-
-static void __exit patch_sigmatel_exit(void)
-{
-       snd_hda_delete_codec_preset(&sigmatel_list);
-}
-
-module_init(patch_sigmatel_init)
-module_exit(patch_sigmatel_exit)
+module_hda_codec_driver(sigmatel_driver);
index 3de6d3d779c994d18fb54a09e7bbf33be98eee26..485663bb91010f85c252d92d25b1679172e5ea74 100644 (file)
@@ -99,7 +99,6 @@ struct via_spec {
 
        /* HP mode source */
        unsigned int dmic_enabled;
-       unsigned int no_pin_power_ctl;
        enum VIA_HDA_CODEC codec_type;
 
        /* analog low-power control */
@@ -108,9 +107,6 @@ struct via_spec {
        /* work to check hp jack state */
        int hp_work_active;
        int vt1708_jack_detect;
-
-       void (*set_widgets_power_state)(struct hda_codec *codec);
-       unsigned int dac_stream_tag[4];
 };
 
 static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
@@ -133,11 +129,12 @@ static struct via_spec *via_new_spec(struct hda_codec *codec)
        /* VT1708BCE & VT1708S are almost same */
        if (spec->codec_type == VT1708BCE)
                spec->codec_type = VT1708S;
-       spec->no_pin_power_ctl = 1;
        spec->gen.indep_hp = 1;
        spec->gen.keep_eapd_on = 1;
        spec->gen.pcm_playback_hook = via_playback_pcm_hook;
        spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
+       codec->power_save_node = 1;
+       spec->gen.power_down_unused = 1;
        return spec;
 }
 
@@ -222,98 +219,13 @@ static void vt1708_update_hp_work(struct hda_codec *codec)
                if (!spec->hp_work_active) {
                        codec->jackpoll_interval = msecs_to_jiffies(100);
                        snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0);
-                       queue_delayed_work(codec->bus->workq,
-                                          &codec->jackpoll_work, 0);
+                       schedule_delayed_work(&codec->jackpoll_work, 0);
                        spec->hp_work_active = true;
                }
        } else if (!hp_detect_with_aa(codec))
                vt1708_stop_hp_work(codec);
 }
 
-static void set_widgets_power_state(struct hda_codec *codec)
-{
-#if 0 /* FIXME: the assumed connections don't match always with the
-       * actual routes by the generic parser, so better to disable
-       * the control for safety.
-       */
-       struct via_spec *spec = codec->spec;
-       if (spec->set_widgets_power_state)
-               spec->set_widgets_power_state(codec);
-#endif
-}
-
-static void update_power_state(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned int parm)
-{
-       if (snd_hda_check_power_state(codec, nid, parm))
-               return;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
-}
-
-static void update_conv_power_state(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned int parm, unsigned int index)
-{
-       struct via_spec *spec = codec->spec;
-       unsigned int format;
-
-       if (snd_hda_check_power_state(codec, nid, parm))
-               return;
-       format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-       if (format && (spec->dac_stream_tag[index] != format))
-               spec->dac_stream_tag[index] = format;
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
-       if (parm == AC_PWRST_D0) {
-               format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-               if (!format && (spec->dac_stream_tag[index] != format))
-                       snd_hda_codec_write(codec, nid, 0,
-                                                 AC_VERB_SET_CHANNEL_STREAMID,
-                                                 spec->dac_stream_tag[index]);
-       }
-}
-
-static bool smart51_enabled(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       return spec->gen.ext_channel_count > 2;
-}
-
-static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct via_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->gen.multi_ios; i++)
-               if (spec->gen.multi_io[i].pin == pin)
-                       return true;
-       return false;
-}
-
-static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
-                               unsigned int *affected_parm)
-{
-       unsigned parm;
-       unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
-       unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
-               >> AC_DEFCFG_MISC_SHIFT
-               & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
-       struct via_spec *spec = codec->spec;
-       unsigned present = 0;
-
-       no_presence |= spec->no_pin_power_ctl;
-       if (!no_presence)
-               present = snd_hda_jack_detect(codec, nid);
-       if ((smart51_enabled(codec) && is_smart51_pins(codec, nid))
-           || ((no_presence || present)
-               && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
-               *affected_parm = AC_PWRST_D0; /* if it's connected */
-               parm = AC_PWRST_D0;
-       } else
-               parm = AC_PWRST_D3;
-
-       update_power_state(codec, nid, parm);
-}
-
 static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
@@ -324,8 +236,7 @@ static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] = !spec->no_pin_power_ctl;
+       ucontrol->value.enumerated.item[0] = codec->power_save_node;
        return 0;
 }
 
@@ -334,12 +245,12 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       unsigned int val = !ucontrol->value.enumerated.item[0];
+       bool val = !!ucontrol->value.enumerated.item[0];
 
-       if (val == spec->no_pin_power_ctl)
+       if (val == codec->power_save_node)
                return 0;
-       spec->no_pin_power_ctl = val;
-       set_widgets_power_state(codec);
+       codec->power_save_node = val;
+       spec->gen.power_down_unused = val;
        analog_low_current_mode(codec);
        return 1;
 }
@@ -384,7 +295,7 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force)
        bool enable;
        unsigned int verb, parm;
 
-       if (spec->no_pin_power_ctl)
+       if (!codec->power_save_node)
                enable = false;
        else
                enable = is_aa_path_mute(codec) && !spec->gen.active_streams;
@@ -441,8 +352,7 @@ static int via_build_controls(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       if (spec->set_widgets_power_state)
-               spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum;
+       spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum;
 
        for (i = 0; i < spec->num_mixers; i++) {
                err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
@@ -486,7 +396,6 @@ static int via_suspend(struct hda_codec *codec)
 static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
        struct via_spec *spec = codec->spec;
-       set_widgets_power_state(codec);
        analog_low_current_mode(codec);
        vt1708_update_hp_work(codec);
        return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid);
@@ -574,34 +483,6 @@ static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = {
        {} /* terminator */
 };
 
-static void via_jack_powerstate_event(struct hda_codec *codec,
-                                     struct hda_jack_callback *tbl)
-{
-       set_widgets_power_state(codec);
-}
-
-static void via_set_jack_unsol_events(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-       hda_nid_t pin;
-       int i;
-
-       for (i = 0; i < cfg->line_outs; i++) {
-               pin = cfg->line_out_pins[i];
-               if (pin && is_jack_detectable(codec, pin))
-                       snd_hda_jack_detect_enable_callback(codec, pin,
-                                                           via_jack_powerstate_event);
-       }
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               pin = cfg->line_out_pins[i];
-               if (pin && is_jack_detectable(codec, pin))
-                       snd_hda_jack_detect_enable_callback(codec, pin,
-                                                           via_jack_powerstate_event);
-       }
-}
-
 static const struct badness_table via_main_out_badness = {
        .no_primary_dac = 0x10000,
        .no_dac = 0x4000,
@@ -635,7 +516,9 @@ static int via_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       via_set_jack_unsol_events(codec);
+       /* disable widget PM at start for compatibility */
+       codec->power_save_node = 0;
+       spec->gen.power_down_unused = 0;
        return 0;
 }
 
@@ -648,7 +531,6 @@ static int via_init(struct hda_codec *codec)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
 
        /* init power states */
-       set_widgets_power_state(codec);
        __analog_low_current_mode(codec, true);
 
        snd_hda_gen_init(codec);
@@ -683,8 +565,10 @@ static int vt1708_build_pcms(struct hda_codec *codec)
         * 24bit samples are used.  Until any workaround is found,
         * disable the 24bit format, so far.
         */
-       for (i = 0; i < codec->num_pcms; i++) {
-               struct hda_pcm *info = &spec->gen.pcm_rec[i];
+       for (i = 0; i < ARRAY_SIZE(spec->gen.pcm_rec); i++) {
+               struct hda_pcm *info = spec->gen.pcm_rec[i];
+               if (!info)
+                       continue;
                if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams ||
                    info->pcm_type != HDA_PCM_TYPE_AUDIO)
                        continue;
@@ -766,78 +650,6 @@ static int patch_vt1709(struct hda_codec *codec)
        return 0;
 }
 
-static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int imux_is_smixer;
-       unsigned int parm;
-       int is_8ch = 0;
-       if ((spec->codec_type != VT1708B_4CH) &&
-           (codec->vendor_id != 0x11064397))
-               is_8ch = 1;
-
-       /* SW0 (17h) = stereo mixer */
-       imux_is_smixer =
-       (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
-        == ((spec->codec_type == VT1708S) ? 5 : 0));
-       /* inputs */
-       /* PW 1/2/5 (1ah/1bh/1eh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x1a, &parm);
-       set_pin_power_state(codec, 0x1b, &parm);
-       set_pin_power_state(codec, 0x1e, &parm);
-       if (imux_is_smixer)
-               parm = AC_PWRST_D0;
-       /* SW0 (17h), AIW 0/1 (13h/14h) */
-       update_power_state(codec, 0x17, parm);
-       update_power_state(codec, 0x13, parm);
-       update_power_state(codec, 0x14, parm);
-
-       /* outputs */
-       /* PW0 (19h), SW1 (18h), AOW1 (11h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x19, &parm);
-       if (smart51_enabled(codec))
-               set_pin_power_state(codec, 0x1b, &parm);
-       update_power_state(codec, 0x18, parm);
-       update_power_state(codec, 0x11, parm);
-
-       /* PW6 (22h), SW2 (26h), AOW2 (24h) */
-       if (is_8ch) {
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x22, &parm);
-               if (smart51_enabled(codec))
-                       set_pin_power_state(codec, 0x1a, &parm);
-               update_power_state(codec, 0x26, parm);
-               update_power_state(codec, 0x24, parm);
-       } else if (codec->vendor_id == 0x11064397) {
-               /* PW7(23h), SW2(27h), AOW2(25h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x23, &parm);
-               if (smart51_enabled(codec))
-                       set_pin_power_state(codec, 0x1a, &parm);
-               update_power_state(codec, 0x27, parm);
-               update_power_state(codec, 0x25, parm);
-       }
-
-       /* PW 3/4/7 (1ch/1dh/23h) */
-       parm = AC_PWRST_D3;
-       /* force to D0 for internal Speaker */
-       set_pin_power_state(codec, 0x1c, &parm);
-       set_pin_power_state(codec, 0x1d, &parm);
-       if (is_8ch)
-               set_pin_power_state(codec, 0x23, &parm);
-
-       /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
-       update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm);
-       update_power_state(codec, 0x10, parm);
-       if (is_8ch) {
-               update_power_state(codec, 0x25, parm);
-               update_power_state(codec, 0x27, parm);
-       } else if (codec->vendor_id == 0x11064397 && spec->gen.indep_hp_enabled)
-               update_power_state(codec, 0x25, parm);
-}
-
 static int patch_vt1708S(struct hda_codec *codec);
 static int patch_vt1708B(struct hda_codec *codec)
 {
@@ -862,9 +674,6 @@ static int patch_vt1708B(struct hda_codec *codec)
        }
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
-
        return 0;
 }
 
@@ -907,16 +716,16 @@ static int patch_vt1708S(struct hda_codec *codec)
        if (get_codec_type(codec) == VT1708BCE) {
                kfree(codec->chip_name);
                codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
-               snprintf(codec->bus->card->mixername,
-                        sizeof(codec->bus->card->mixername),
+               snprintf(codec->card->mixername,
+                        sizeof(codec->card->mixername),
                         "%s %s", codec->vendor_name, codec->chip_name);
        }
        /* correct names for VT1705 */
        if (codec->vendor_id == 0x11064397)     {
                kfree(codec->chip_name);
                codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
-               snprintf(codec->bus->card->mixername,
-                        sizeof(codec->bus->card->mixername),
+               snprintf(codec->card->mixername,
+                        sizeof(codec->card->mixername),
                         "%s %s", codec->vendor_name, codec->chip_name);
        }
 
@@ -930,8 +739,6 @@ static int patch_vt1708S(struct hda_codec *codec)
        spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs;
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
        return 0;
 }
 
@@ -945,36 +752,6 @@ static const struct hda_verb vt1702_init_verbs[] = {
        { }
 };
 
-static void set_widgets_power_state_vt1702(struct hda_codec *codec)
-{
-       int imux_is_smixer =
-       snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-       unsigned int parm;
-       /* inputs */
-       /* PW 1/2/5 (14h/15h/18h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x14, &parm);
-       set_pin_power_state(codec, 0x15, &parm);
-       set_pin_power_state(codec, 0x18, &parm);
-       if (imux_is_smixer)
-               parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
-       /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
-       update_power_state(codec, 0x13, parm);
-       update_power_state(codec, 0x12, parm);
-       update_power_state(codec, 0x1f, parm);
-       update_power_state(codec, 0x20, parm);
-
-       /* outputs */
-       /* PW 3/4 (16h/17h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x17, &parm);
-       set_pin_power_state(codec, 0x16, &parm);
-       /* MW0 (1ah), AOW 0/1 (10h/1dh) */
-       update_power_state(codec, 0x1a, imux_is_smixer ? AC_PWRST_D0 : parm);
-       update_power_state(codec, 0x10, parm);
-       update_power_state(codec, 0x1d, parm);
-}
-
 static int patch_vt1702(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -1004,8 +781,6 @@ static int patch_vt1702(struct hda_codec *codec)
        spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs;
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
        return 0;
 }
 
@@ -1020,71 +795,6 @@ static const struct hda_verb vt1718S_init_verbs[] = {
        { }
 };
 
-static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int imux_is_smixer;
-       unsigned int parm, parm2;
-       /* MUX6 (1eh) = stereo mixer */
-       imux_is_smixer =
-       snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
-       /* inputs */
-       /* PW 5/6/7 (29h/2ah/2bh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x29, &parm);
-       set_pin_power_state(codec, 0x2a, &parm);
-       set_pin_power_state(codec, 0x2b, &parm);
-       if (imux_is_smixer)
-               parm = AC_PWRST_D0;
-       /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
-       update_power_state(codec, 0x1e, parm);
-       update_power_state(codec, 0x1f, parm);
-       update_power_state(codec, 0x10, parm);
-       update_power_state(codec, 0x11, parm);
-
-       /* outputs */
-       /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x27, &parm);
-       update_power_state(codec, 0x1a, parm);
-       parm2 = parm; /* for pin 0x0b */
-
-       /* PW2 (26h), AOW2 (ah) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x26, &parm);
-       if (smart51_enabled(codec))
-               set_pin_power_state(codec, 0x2b, &parm);
-       update_power_state(codec, 0xa, parm);
-
-       /* PW0 (24h), AOW0 (8h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x24, &parm);
-       if (!spec->gen.indep_hp_enabled) /* check for redirected HP */
-               set_pin_power_state(codec, 0x28, &parm);
-       update_power_state(codec, 0x8, parm);
-       if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3)
-               parm = parm2;
-       update_power_state(codec, 0xb, parm);
-       /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
-       update_power_state(codec, 0x21, imux_is_smixer ? AC_PWRST_D0 : parm);
-
-       /* PW1 (25h), AOW1 (9h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x25, &parm);
-       if (smart51_enabled(codec))
-               set_pin_power_state(codec, 0x2a, &parm);
-       update_power_state(codec, 0x9, parm);
-
-       if (spec->gen.indep_hp_enabled) {
-               /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x28, &parm);
-               update_power_state(codec, 0x1b, parm);
-               update_power_state(codec, 0x34, parm);
-               update_power_state(codec, 0xc, parm);
-       }
-}
-
 /* Add a connection to the primary DAC from AA-mixer for some codecs
  * This isn't listed from the raw info, but the chip has a secret connection.
  */
@@ -1145,9 +855,6 @@ static int patch_vt1718S(struct hda_codec *codec)
        spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs;
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
-
        return 0;
 }
 
@@ -1187,7 +894,6 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
        snd_hda_codec_write(codec, 0x26, 0,
                                               AC_VERB_SET_CONNECT_SEL, index);
        spec->dmic_enabled = index;
-       set_widgets_power_state(codec);
        return 1;
 }
 
@@ -1222,95 +928,6 @@ static const struct hda_verb vt1716S_init_verbs[] = {
        { }
 };
 
-static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int imux_is_smixer;
-       unsigned int parm;
-       unsigned int mono_out, present;
-       /* SW0 (17h) = stereo mixer */
-       imux_is_smixer =
-       (snd_hda_codec_read(codec, 0x17, 0,
-                           AC_VERB_GET_CONNECT_SEL, 0x00) ==  5);
-       /* inputs */
-       /* PW 1/2/5 (1ah/1bh/1eh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x1a, &parm);
-       set_pin_power_state(codec, 0x1b, &parm);
-       set_pin_power_state(codec, 0x1e, &parm);
-       if (imux_is_smixer)
-               parm = AC_PWRST_D0;
-       /* SW0 (17h), AIW0(13h) */
-       update_power_state(codec, 0x17, parm);
-       update_power_state(codec, 0x13, parm);
-
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x1e, &parm);
-       /* PW11 (22h) */
-       if (spec->dmic_enabled)
-               set_pin_power_state(codec, 0x22, &parm);
-       else
-               update_power_state(codec, 0x22, AC_PWRST_D3);
-
-       /* SW2(26h), AIW1(14h) */
-       update_power_state(codec, 0x26, parm);
-       update_power_state(codec, 0x14, parm);
-
-       /* outputs */
-       /* PW0 (19h), SW1 (18h), AOW1 (11h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x19, &parm);
-       /* Smart 5.1 PW2(1bh) */
-       if (smart51_enabled(codec))
-               set_pin_power_state(codec, 0x1b, &parm);
-       update_power_state(codec, 0x18, parm);
-       update_power_state(codec, 0x11, parm);
-
-       /* PW7 (23h), SW3 (27h), AOW3 (25h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x23, &parm);
-       /* Smart 5.1 PW1(1ah) */
-       if (smart51_enabled(codec))
-               set_pin_power_state(codec, 0x1a, &parm);
-       update_power_state(codec, 0x27, parm);
-
-       /* Smart 5.1 PW5(1eh) */
-       if (smart51_enabled(codec))
-               set_pin_power_state(codec, 0x1e, &parm);
-       update_power_state(codec, 0x25, parm);
-
-       /* Mono out */
-       /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
-       present = snd_hda_jack_detect(codec, 0x1c);
-
-       if (present)
-               mono_out = 0;
-       else {
-               present = snd_hda_jack_detect(codec, 0x1d);
-               if (!spec->gen.indep_hp_enabled && present)
-                       mono_out = 0;
-               else
-                       mono_out = 1;
-       }
-       parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
-       update_power_state(codec, 0x28, parm);
-       update_power_state(codec, 0x29, parm);
-       update_power_state(codec, 0x2a, parm);
-
-       /* PW 3/4 (1ch/1dh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x1c, &parm);
-       set_pin_power_state(codec, 0x1d, &parm);
-       /* HP Independent Mode, power on AOW3 */
-       if (spec->gen.indep_hp_enabled)
-               update_power_state(codec, 0x25, parm);
-
-       /* force to D0 for internal Speaker */
-       /* MW0 (16h), AOW0 (10h) */
-       update_power_state(codec, 0x16, imux_is_smixer ? AC_PWRST_D0 : parm);
-       update_power_state(codec, 0x10, mono_out ? AC_PWRST_D0 : parm);
-}
-
 static int patch_vt1716S(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -1338,8 +955,6 @@ static int patch_vt1716S(struct hda_codec *codec)
        spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
        return 0;
 }
 
@@ -1365,98 +980,6 @@ static const struct hda_verb vt1802_init_verbs[] = {
        { }
 };
 
-static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int imux_is_smixer;
-       unsigned int parm;
-       unsigned int present;
-       /* MUX9 (1eh) = stereo mixer */
-       imux_is_smixer =
-       snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
-       /* inputs */
-       /* PW 5/6/7 (29h/2ah/2bh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x29, &parm);
-       set_pin_power_state(codec, 0x2a, &parm);
-       set_pin_power_state(codec, 0x2b, &parm);
-       parm = AC_PWRST_D0;
-       /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
-       update_power_state(codec, 0x1e, parm);
-       update_power_state(codec, 0x1f, parm);
-       update_power_state(codec, 0x10, parm);
-       update_power_state(codec, 0x11, parm);
-
-       /* outputs */
-       /* AOW0 (8h)*/
-       update_power_state(codec, 0x8, parm);
-
-       if (spec->codec_type == VT1802) {
-               /* PW4 (28h), MW4 (18h), MUX4(38h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x28, &parm);
-               update_power_state(codec, 0x18, parm);
-               update_power_state(codec, 0x38, parm);
-       } else {
-               /* PW4 (26h), MW4 (1ch), MUX4(37h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x26, &parm);
-               update_power_state(codec, 0x1c, parm);
-               update_power_state(codec, 0x37, parm);
-       }
-
-       if (spec->codec_type == VT1802) {
-               /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x25, &parm);
-               update_power_state(codec, 0x15, parm);
-               update_power_state(codec, 0x35, parm);
-       } else {
-               /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x25, &parm);
-               update_power_state(codec, 0x19, parm);
-               update_power_state(codec, 0x35, parm);
-       }
-
-       if (spec->gen.indep_hp_enabled)
-               update_power_state(codec, 0x9, AC_PWRST_D0);
-
-       /* Class-D */
-       /* PW0 (24h), MW0(18h/14h), MUX0(34h) */
-       present = snd_hda_jack_detect(codec, 0x25);
-
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x24, &parm);
-       parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
-       if (spec->codec_type == VT1802)
-               update_power_state(codec, 0x14, parm);
-       else
-               update_power_state(codec, 0x18, parm);
-       update_power_state(codec, 0x34, parm);
-
-       /* Mono Out */
-       present = snd_hda_jack_detect(codec, 0x26);
-
-       parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
-       if (spec->codec_type == VT1802) {
-               /* PW15 (33h), MW8(1ch), MUX8(3ch) */
-               update_power_state(codec, 0x33, parm);
-               update_power_state(codec, 0x1c, parm);
-               update_power_state(codec, 0x3c, parm);
-       } else {
-               /* PW15 (31h), MW8(17h), MUX8(3bh) */
-               update_power_state(codec, 0x31, parm);
-               update_power_state(codec, 0x17, parm);
-               update_power_state(codec, 0x3b, parm);
-       }
-       /* MW9 (21h) */
-       if (imux_is_smixer || !is_aa_path_mute(codec))
-               update_power_state(codec, 0x21, AC_PWRST_D0);
-       else
-               update_power_state(codec, 0x21, AC_PWRST_D3);
-}
-
 /*
  * pin fix-up
  */
@@ -1540,8 +1063,6 @@ static int patch_vt2002P(struct hda_codec *codec)
                spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs;
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
        return 0;
 }
 
@@ -1555,81 +1076,6 @@ static const struct hda_verb vt1812_init_verbs[] = {
        { }
 };
 
-static void set_widgets_power_state_vt1812(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       unsigned int parm;
-       unsigned int present;
-       /* inputs */
-       /* PW 5/6/7 (29h/2ah/2bh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x29, &parm);
-       set_pin_power_state(codec, 0x2a, &parm);
-       set_pin_power_state(codec, 0x2b, &parm);
-       parm = AC_PWRST_D0;
-       /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
-       update_power_state(codec, 0x1e, parm);
-       update_power_state(codec, 0x1f, parm);
-       update_power_state(codec, 0x10, parm);
-       update_power_state(codec, 0x11, parm);
-
-       /* outputs */
-       /* AOW0 (8h)*/
-       update_power_state(codec, 0x8, AC_PWRST_D0);
-
-       /* PW4 (28h), MW4 (18h), MUX4(38h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x28, &parm);
-       update_power_state(codec, 0x18, parm);
-       update_power_state(codec, 0x38, parm);
-
-       /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x25, &parm);
-       update_power_state(codec, 0x15, parm);
-       update_power_state(codec, 0x35, parm);
-       if (spec->gen.indep_hp_enabled)
-               update_power_state(codec, 0x9, AC_PWRST_D0);
-
-       /* Internal Speaker */
-       /* PW0 (24h), MW0(14h), MUX0(34h) */
-       present = snd_hda_jack_detect(codec, 0x25);
-
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x24, &parm);
-       if (present) {
-               update_power_state(codec, 0x14, AC_PWRST_D3);
-               update_power_state(codec, 0x34, AC_PWRST_D3);
-       } else {
-               update_power_state(codec, 0x14, AC_PWRST_D0);
-               update_power_state(codec, 0x34, AC_PWRST_D0);
-       }
-
-
-       /* Mono Out */
-       /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
-       present = snd_hda_jack_detect(codec, 0x28);
-
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x31, &parm);
-       if (present) {
-               update_power_state(codec, 0x1c, AC_PWRST_D3);
-               update_power_state(codec, 0x3c, AC_PWRST_D3);
-               update_power_state(codec, 0x3e, AC_PWRST_D3);
-       } else {
-               update_power_state(codec, 0x1c, AC_PWRST_D0);
-               update_power_state(codec, 0x3c, AC_PWRST_D0);
-               update_power_state(codec, 0x3e, AC_PWRST_D0);
-       }
-
-       /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x33, &parm);
-       update_power_state(codec, 0x1d, parm);
-       update_power_state(codec, 0x3d, parm);
-
-}
-
 /* patch for vt1812 */
 static int patch_vt1812(struct hda_codec *codec)
 {
@@ -1656,8 +1102,6 @@ static int patch_vt1812(struct hda_codec *codec)
        spec->init_verbs[spec->num_iverbs++]  = vt1812_init_verbs;
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
        return 0;
 }
 
@@ -1673,84 +1117,6 @@ static const struct hda_verb vt3476_init_verbs[] = {
        { }
 };
 
-static void set_widgets_power_state_vt3476(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int imux_is_smixer;
-       unsigned int parm, parm2;
-       /* MUX10 (1eh) = stereo mixer */
-       imux_is_smixer =
-       snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 4;
-       /* inputs */
-       /* PW 5/6/7 (29h/2ah/2bh) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x29, &parm);
-       set_pin_power_state(codec, 0x2a, &parm);
-       set_pin_power_state(codec, 0x2b, &parm);
-       if (imux_is_smixer)
-               parm = AC_PWRST_D0;
-       /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
-       update_power_state(codec, 0x1e, parm);
-       update_power_state(codec, 0x1f, parm);
-       update_power_state(codec, 0x10, parm);
-       update_power_state(codec, 0x11, parm);
-
-       /* outputs */
-       /* PW3 (27h), MW3(37h), AOW3 (bh) */
-       if (spec->codec_type == VT1705CF) {
-               parm = AC_PWRST_D3;
-               update_power_state(codec, 0x27, parm);
-               update_power_state(codec, 0x37, parm);
-       }       else {
-               parm = AC_PWRST_D3;
-               set_pin_power_state(codec, 0x27, &parm);
-               update_power_state(codec, 0x37, parm);
-       }
-
-       /* PW2 (26h), MW2(36h), AOW2 (ah) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x26, &parm);
-       update_power_state(codec, 0x36, parm);
-       if (smart51_enabled(codec)) {
-               /* PW7(2bh), MW7(3bh), MUX7(1Bh) */
-               set_pin_power_state(codec, 0x2b, &parm);
-               update_power_state(codec, 0x3b, parm);
-               update_power_state(codec, 0x1b, parm);
-       }
-       update_conv_power_state(codec, 0xa, parm, 2);
-
-       /* PW1 (25h), MW1(35h), AOW1 (9h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x25, &parm);
-       update_power_state(codec, 0x35, parm);
-       if (smart51_enabled(codec)) {
-               /* PW6(2ah), MW6(3ah), MUX6(1ah) */
-               set_pin_power_state(codec, 0x2a, &parm);
-               update_power_state(codec, 0x3a, parm);
-               update_power_state(codec, 0x1a, parm);
-       }
-       update_conv_power_state(codec, 0x9, parm, 1);
-
-       /* PW4 (28h), MW4 (38h), MUX4(18h), AOW3(bh)/AOW0(8h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x28, &parm);
-       update_power_state(codec, 0x38, parm);
-       update_power_state(codec, 0x18, parm);
-       if (spec->gen.indep_hp_enabled)
-               update_conv_power_state(codec, 0xb, parm, 3);
-       parm2 = parm; /* for pin 0x0b */
-
-       /* PW0 (24h), MW0(34h), MW9(3fh), AOW0 (8h) */
-       parm = AC_PWRST_D3;
-       set_pin_power_state(codec, 0x24, &parm);
-       update_power_state(codec, 0x34, parm);
-       if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3)
-               parm = parm2;
-       update_conv_power_state(codec, 0x8, parm, 0);
-       /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
-       update_power_state(codec, 0x3f, imux_is_smixer ? AC_PWRST_D0 : parm);
-}
-
 static int patch_vt3476(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -1774,9 +1140,6 @@ static int patch_vt3476(struct hda_codec *codec)
        spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs;
 
        codec->patch_ops = via_patch_ops;
-
-       spec->set_widgets_power_state = set_widgets_power_state_vt3476;
-
        return 0;
 }
 
@@ -1884,23 +1247,11 @@ static const struct hda_codec_preset snd_hda_preset_via[] = {
 
 MODULE_ALIAS("snd-hda-codec-id:1106*");
 
-static struct hda_codec_preset_list via_list = {
+static struct hda_codec_driver via_driver = {
        .preset = snd_hda_preset_via,
-       .owner = THIS_MODULE,
 };
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("VIA HD-audio codec");
 
-static int __init patch_via_init(void)
-{
-       return snd_hda_add_codec_preset(&via_list);
-}
-
-static void __exit patch_via_exit(void)
-{
-       snd_hda_delete_codec_preset(&via_list);
-}
-
-module_init(patch_via_init)
-module_exit(patch_via_exit)
+module_hda_codec_driver(via_driver);
index bcf30a387b87640f2f42202b1189af0fde49066e..9906119e0954cf0f5185512ee031853e8d67938b 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <sound/core.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
 
 #include "ice1712.h"
 #include "envy24ht.h"
 #include "wtm.h"
 #include "stac946x.h"
 
+struct wtm_spec {
+       /* rate change needs atomic mute/unmute of all dacs*/
+       struct mutex mute_mutex;
+};
+
 
 /*
  *     2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
@@ -68,15 +75,65 @@ static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
 /*
  *     DAC mute control
  */
+static void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute,
+                               unsigned short int *change_mask)
+{
+       unsigned char new, old;
+       int id, idx, change;
+
+       /*stac9460 1*/
+       for (id = 0; id < 7; id++) {
+               if (*change_mask & (0x01 << id)) {
+                       if (id == 0)
+                               idx = STAC946X_MASTER_VOLUME;
+                       else
+                               idx = STAC946X_LF_VOLUME - 1 + id;
+                       old = stac9460_get(ice, idx);
+                       new = (~mute << 7 & 0x80) | (old & ~0x80);
+                       change = (new != old);
+                       if (change) {
+                               stac9460_put(ice, idx, new);
+                               *change_mask = *change_mask | (0x01 << id);
+                       } else {
+                               *change_mask = *change_mask & ~(0x01 << id);
+                       }
+               }
+       }
+
+       /*stac9460 2*/
+       for (id = 0; id < 3; id++) {
+               if (*change_mask & (0x01 << (id + 7))) {
+                       if (id == 0)
+                               idx = STAC946X_MASTER_VOLUME;
+                       else
+                               idx = STAC946X_LF_VOLUME - 1 + id;
+                       old = stac9460_2_get(ice, idx);
+                       new = (~mute << 7 & 0x80) | (old & ~0x80);
+                       change = (new != old);
+                       if (change) {
+                               stac9460_2_put(ice, idx, new);
+                               *change_mask = *change_mask | (0x01 << id);
+                       } else {
+                               *change_mask = *change_mask & ~(0x01 << id);
+                       }
+               }
+       }
+}
+
+
+
 #define stac9460_dac_mute_info         snd_ctl_boolean_mono_info
 
 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct wtm_spec *spec = ice->spec;
        unsigned char val;
        int idx, id;
 
+       mutex_lock(&spec->mute_mutex);
+
        if (kcontrol->private_value) {
                idx = STAC946X_MASTER_VOLUME;
                id = 0;
@@ -89,6 +146,8 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
        else
                val = stac9460_2_get(ice, idx - 6);
        ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
+
+       mutex_unlock(&spec->mute_mutex);
        return 0;
 }
 
@@ -338,8 +397,14 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
 /*
  * MIC / LINE switch fonction
  */
+static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       static const char * const texts[2] = { "Line In", "Mic" };
+
+       return snd_ctl_enum_info(uinfo, 1, 2, texts);
+}
 
-#define stac9460_mic_sw_info           snd_ctl_boolean_mono_info
 
 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
@@ -353,7 +418,7 @@ static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
                val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
        else
                val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-       ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
+       ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1;
        return 0;
 }
 
@@ -369,7 +434,7 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
                old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
        else
                old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
-       new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80);
+       new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80);
        change = (new != old);
        if (change) {
                if (id == 0)
@@ -380,17 +445,63 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+
+/*
+ * Handler for setting correct codec rate - called when rate change is detected
+ */
+static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
+{
+       unsigned char old, new;
+       unsigned short int changed;
+       struct wtm_spec *spec = ice->spec;
+
+       if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
+               return;
+       else if (rate <= 48000)
+               new = 0x08;     /* 256x, base rate mode */
+       else if (rate <= 96000)
+               new = 0x11;     /* 256x, mid rate mode */
+       else
+               new = 0x12;     /* 128x, high rate mode */
+
+       old = stac9460_get(ice, STAC946X_MASTER_CLOCKING);
+       if (old == new)
+               return;
+       /* change detected, setting master clock, muting first */
+       /* due to possible conflicts with mute controls - mutexing */
+       mutex_lock(&spec->mute_mutex);
+       /* we have to remember current mute status for each DAC */
+       changed = 0xFFFF;
+       stac9460_dac_mute_all(ice, 0, &changed);
+       /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
+       stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
+       stac9460_2_put(ice, STAC946X_MASTER_CLOCKING, new);
+       udelay(10);
+       /* unmuting - only originally unmuted dacs -
+       * i.e. those changed when muting */
+       stac9460_dac_mute_all(ice, 1, &changed);
+       mutex_unlock(&spec->mute_mutex);
+}
+
+
+/*Limits value in dB for fader*/
+static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
+
 /*
  * Control tabs
  */
 static struct snd_kcontrol_new stac9640_controls[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                           SNDRV_CTL_ELEM_ACCESS_TLV_READ),
                .name = "Master Playback Switch",
                .info = stac9460_dac_mute_info,
                .get = stac9460_dac_mute_get,
                .put = stac9460_dac_mute_put,
-               .private_value = 1
+               .private_value = 1,
+               .tlv = { .p = db_scale_dac }
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -402,7 +513,7 @@ static struct snd_kcontrol_new stac9640_controls[] = {
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "MIC/Line switch",
+               .name = "MIC/Line Input Enum",
                .count = 2,
                .info = stac9460_mic_sw_info,
                .get = stac9460_mic_sw_get,
@@ -419,11 +530,15 @@ static struct snd_kcontrol_new stac9640_controls[] = {
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                           SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+
                .name = "DAC Volume",
                .count = 8,
                .info = stac9460_dac_vol_info,
                .get = stac9460_dac_vol_get,
                .put = stac9460_dac_vol_put,
+               .tlv = { .p = db_scale_dac }
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -435,12 +550,15 @@ static struct snd_kcontrol_new stac9640_controls[] = {
        },
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                           SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+
                .name = "ADC Volume",
                .count = 2,
                .info = stac9460_adc_vol_info,
                .get = stac9460_adc_vol_get,
                .put = stac9460_adc_vol_put,
-
+               .tlv = { .p = db_scale_adc }
        }
 };
 
@@ -463,41 +581,53 @@ static int wtm_add_controls(struct snd_ice1712 *ice)
 
 static int wtm_init(struct snd_ice1712 *ice)
 {
-       static unsigned short stac_inits_prodigy[] = {
+       static unsigned short stac_inits_wtm[] = {
                STAC946X_RESET, 0,
+               STAC946X_MASTER_CLOCKING, 0x11,
                (unsigned short)-1
        };
        unsigned short *p;
+       struct wtm_spec *spec;
 
        /*WTM 192M*/
        ice->num_total_dacs = 8;
        ice->num_total_adcs = 4;
        ice->force_rdma1 = 1;
 
+       /*init mutex for dac mute conflict*/
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+       mutex_init(&spec->mute_mutex);
+
+
        /*initialize codec*/
-       p = stac_inits_prodigy;
+       p = stac_inits_wtm;
        for (; *p != (unsigned short)-1; p += 2) {
                stac9460_put(ice, p[0], p[1]);
                stac9460_2_put(ice, p[0], p[1]);
        }
+       ice->gpio.set_pro_rate = stac9460_set_rate_val;
        return 0;
 }
 
 
 static unsigned char wtm_eeprom[] = {
-       0x47,   /*SYSCONF: clock 192KHz, 4ADC, 8DAC */
-       0x80,   /* ACLINK : I2S */
-       0xf8,   /* I2S: vol; 96k, 24bit, 192k */
-       0xc1    /*SPDIF: out-en, spidf ext out*/,
-       0x9f,   /* GPIO_DIR */
-       0xff,   /* GPIO_DIR1 */
-       0x7f,   /* GPIO_DIR2 */
-       0x9f,   /* GPIO_MASK */
-       0xff,   /* GPIO_MASK1 */
-       0x7f,   /* GPIO_MASK2 */
-       0x16,   /* GPIO_STATE */
-       0x80,   /* GPIO_STATE1 */
-       0x00,   /* GPIO_STATE2 */
+       [ICE_EEP2_SYSCONF]      = 0x67, /*SYSCONF: clock 192KHz, mpu401,
+                                                       4ADC, 8DAC */
+       [ICE_EEP2_ACLINK]       = 0x80, /* ACLINK : I2S */
+       [ICE_EEP2_I2S]          = 0xf8, /* I2S: vol; 96k, 24bit, 192k */
+       [ICE_EEP2_SPDIF]        = 0xc1, /*SPDIF: out-en, spidf ext out*/
+       [ICE_EEP2_GPIO_DIR]     = 0x9f,
+       [ICE_EEP2_GPIO_DIR1]    = 0xff,
+       [ICE_EEP2_GPIO_DIR2]    = 0x7f,
+       [ICE_EEP2_GPIO_MASK]    = 0x9f,
+       [ICE_EEP2_GPIO_MASK1]   = 0xff,
+       [ICE_EEP2_GPIO_MASK2]   = 0x7f,
+       [ICE_EEP2_GPIO_STATE]   = 0x16,
+       [ICE_EEP2_GPIO_STATE1]  = 0x80,
+       [ICE_EEP2_GPIO_STATE2]  = 0x00,
 };
 
 
index ca67f896d11757bc05be43804d367175b282dad0..cb666c73712d15276b411cdce11c7994380d4ffb 100644 (file)
@@ -6043,23 +6043,30 @@ hdspm_hw_constraints_aes32_sample_rates = {
        .mask = 0
 };
 
-static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
+static int snd_hdspm_open(struct snd_pcm_substream *substream)
 {
        struct hdspm *hdspm = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
        spin_lock_irq(&hdspm->lock);
-
        snd_pcm_set_sync(substream);
+       runtime->hw = (playback) ? snd_hdspm_playback_subinfo :
+               snd_hdspm_capture_subinfo;
 
+       if (playback) {
+               if (hdspm->capture_substream == NULL)
+                       hdspm_stop_audio(hdspm);
 
-       runtime->hw = snd_hdspm_playback_subinfo;
-
-       if (hdspm->capture_substream == NULL)
-               hdspm_stop_audio(hdspm);
+               hdspm->playback_pid = current->pid;
+               hdspm->playback_substream = substream;
+       } else {
+               if (hdspm->playback_substream == NULL)
+                       hdspm_stop_audio(hdspm);
 
-       hdspm->playback_pid = current->pid;
-       hdspm->playback_substream = substream;
+               hdspm->capture_pid = current->pid;
+               hdspm->capture_substream = substream;
+       }
 
        spin_unlock_irq(&hdspm->lock);
 
@@ -6094,108 +6101,42 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
                                &hdspm_hw_constraints_aes32_sample_rates);
        } else {
                snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                               snd_hdspm_hw_rule_rate_out_channels, hdspm,
+                               (playback ?
+                                snd_hdspm_hw_rule_rate_out_channels :
+                                snd_hdspm_hw_rule_rate_in_channels), hdspm,
                                SNDRV_PCM_HW_PARAM_CHANNELS, -1);
        }
 
        snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                       snd_hdspm_hw_rule_out_channels, hdspm,
+                       (playback ? snd_hdspm_hw_rule_out_channels :
+                        snd_hdspm_hw_rule_in_channels), hdspm,
                        SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
        snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                       snd_hdspm_hw_rule_out_channels_rate, hdspm,
+                       (playback ? snd_hdspm_hw_rule_out_channels_rate :
+                        snd_hdspm_hw_rule_in_channels_rate), hdspm,
                        SNDRV_PCM_HW_PARAM_RATE, -1);
 
        return 0;
 }
 
-static int snd_hdspm_playback_release(struct snd_pcm_substream *substream)
+static int snd_hdspm_release(struct snd_pcm_substream *substream)
 {
        struct hdspm *hdspm = snd_pcm_substream_chip(substream);
+       bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
        spin_lock_irq(&hdspm->lock);
 
-       hdspm->playback_pid = -1;
-       hdspm->playback_substream = NULL;
-
-       spin_unlock_irq(&hdspm->lock);
-
-       return 0;
-}
-
-
-static int snd_hdspm_capture_open(struct snd_pcm_substream *substream)
-{
-       struct hdspm *hdspm = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       spin_lock_irq(&hdspm->lock);
-       snd_pcm_set_sync(substream);
-       runtime->hw = snd_hdspm_capture_subinfo;
-
-       if (hdspm->playback_substream == NULL)
-               hdspm_stop_audio(hdspm);
-
-       hdspm->capture_pid = current->pid;
-       hdspm->capture_substream = substream;
-
-       spin_unlock_irq(&hdspm->lock);
-
-       snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
-       snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
-
-       switch (hdspm->io_type) {
-       case AIO:
-       case RayDAT:
-               snd_pcm_hw_constraint_minmax(runtime,
-                                            SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
-                                            32, 4096);
-               snd_pcm_hw_constraint_minmax(runtime,
-                                            SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
-                                            16384, 16384);
-               break;
-
-       default:
-               snd_pcm_hw_constraint_minmax(runtime,
-                                            SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
-                                            64, 8192);
-               snd_pcm_hw_constraint_minmax(runtime,
-                                            SNDRV_PCM_HW_PARAM_PERIODS,
-                                            2, 2);
-               break;
-       }
-
-       if (AES32 == hdspm->io_type) {
-               runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
-               snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                               &hdspm_hw_constraints_aes32_sample_rates);
+       if (playback) {
+               hdspm->playback_pid = -1;
+               hdspm->playback_substream = NULL;
        } else {
-               snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                               snd_hdspm_hw_rule_rate_in_channels, hdspm,
-                               SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+               hdspm->capture_pid = -1;
+               hdspm->capture_substream = NULL;
        }
 
-       snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                       snd_hdspm_hw_rule_in_channels, hdspm,
-                       SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-
-       snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                       snd_hdspm_hw_rule_in_channels_rate, hdspm,
-                       SNDRV_PCM_HW_PARAM_RATE, -1);
-
-       return 0;
-}
-
-static int snd_hdspm_capture_release(struct snd_pcm_substream *substream)
-{
-       struct hdspm *hdspm = snd_pcm_substream_chip(substream);
-
-       spin_lock_irq(&hdspm->lock);
-
-       hdspm->capture_pid = -1;
-       hdspm->capture_substream = NULL;
-
        spin_unlock_irq(&hdspm->lock);
+
        return 0;
 }
 
@@ -6413,21 +6354,9 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
        return 0;
 }
 
-static struct snd_pcm_ops snd_hdspm_playback_ops = {
-       .open = snd_hdspm_playback_open,
-       .close = snd_hdspm_playback_release,
-       .ioctl = snd_hdspm_ioctl,
-       .hw_params = snd_hdspm_hw_params,
-       .hw_free = snd_hdspm_hw_free,
-       .prepare = snd_hdspm_prepare,
-       .trigger = snd_hdspm_trigger,
-       .pointer = snd_hdspm_hw_pointer,
-       .page = snd_pcm_sgbuf_ops_page,
-};
-
-static struct snd_pcm_ops snd_hdspm_capture_ops = {
-       .open = snd_hdspm_capture_open,
-       .close = snd_hdspm_capture_release,
+static struct snd_pcm_ops snd_hdspm_ops = {
+       .open = snd_hdspm_open,
+       .close = snd_hdspm_release,
        .ioctl = snd_hdspm_ioctl,
        .hw_params = snd_hdspm_hw_params,
        .hw_free = snd_hdspm_hw_free,
@@ -6521,9 +6450,9 @@ static int snd_hdspm_create_pcm(struct snd_card *card,
        strcpy(pcm->name, hdspm->card_name);
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-                       &snd_hdspm_playback_ops);
+                       &snd_hdspm_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-                       &snd_hdspm_capture_ops);
+                       &snd_hdspm_ops);
 
        pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
 
index fb0b7e8b08ff4cd11a2656fe76fe10898aeded6b..841d05946b888fc5b905445f61611f44df685ff6 100644 (file)
@@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+/*
+ * When the bit clock is input, limit the maximum rate according to the
+ * Serial Clock Ratio Considerations section from the SSC documentation:
+ *
+ *   The Transmitter and the Receiver can be programmed to operate
+ *   with the clock signals provided on either the TK or RK pins.
+ *   This allows the SSC to support many slave-mode data transfers.
+ *   In this case, the maximum clock speed allowed on the RK pin is:
+ *   - Peripheral clock divided by 2 if Receiver Frame Synchro is input
+ *   - Peripheral clock divided by 3 if Receiver Frame Synchro is output
+ *   In addition, the maximum clock speed allowed on the TK pin is:
+ *   - Peripheral clock divided by 6 if Transmit Frame Synchro is input
+ *   - Peripheral clock divided by 2 if Transmit Frame Synchro is output
+ *
+ * When the bit clock is output, limit the rate according to the
+ * SSC divider restrictions.
+ */
+static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
+                                 struct snd_pcm_hw_rule *rule)
+{
+       struct atmel_ssc_info *ssc_p = rule->private;
+       struct ssc_device *ssc = ssc_p->ssc;
+       struct snd_interval *i = hw_param_interval(params, rule->var);
+       struct snd_interval t;
+       struct snd_ratnum r = {
+               .den_min = 1,
+               .den_max = 4095,
+               .den_step = 1,
+       };
+       unsigned int num = 0, den = 0;
+       int frame_size;
+       int mck_div = 2;
+       int ret;
+
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0)
+               return frame_size;
+
+       switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFS:
+               if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)
+                   && ssc->clk_from_rk_pin)
+                       /* Receiver Frame Synchro (i.e. capture)
+                        * is output (format is _CFS) and the RK pin
+                        * is used for input (format is _CBM_).
+                        */
+                       mck_div = 3;
+               break;
+
+       case SND_SOC_DAIFMT_CBM_CFM:
+               if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)
+                   && !ssc->clk_from_rk_pin)
+                       /* Transmit Frame Synchro (i.e. playback)
+                        * is input (format is _CFM) and the TK pin
+                        * is used for input (format _CBM_ but not
+                        * using the RK pin).
+                        */
+                       mck_div = 6;
+               break;
+       }
+
+       switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               r.num = ssc_p->mck_rate / mck_div / frame_size;
+
+               ret = snd_interval_ratnum(i, 1, &r, &num, &den);
+               if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
+                       params->rate_num = num;
+                       params->rate_den = den;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBM_CFM:
+               t.min = 8000;
+               t.max = ssc_p->mck_rate / mck_div / frame_size;
+               t.openmin = t.openmax = 0;
+               t.integer = 0;
+               ret = snd_interval_refine(i, &t);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
 
 /*-------------------------------------------------------------------------*\
  * DAI functions
@@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
        struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        struct atmel_pcm_dma_params *dma_params;
        int dir, dir_mask;
+       int ret;
 
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
                ssc_readl(ssc_p->ssc->regs, SR));
@@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
        /* Enable PMC peripheral clock for this SSC */
        pr_debug("atmel_ssc_dai: Starting clock\n");
        clk_enable(ssc_p->ssc->clk);
+       ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
 
        /* Reset the SSC to keep it at a clean status */
        ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
@@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
                dir_mask = SSC_DIR_MASK_CAPTURE;
        }
 
+       ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_RATE,
+                                 atmel_ssc_hw_rule_rate,
+                                 ssc_p,
+                                 SNDRV_PCM_HW_PARAM_FRAME_BITS,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+       if (ret < 0) {
+               dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret);
+               return ret;
+       }
+
        dma_params = &ssc_dma_params[dai->id][dir];
        dma_params->ssc = ssc_p->ssc;
        dma_params->substream = substream;
@@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
 #  define atmel_ssc_resume     NULL
 #endif /* CONFIG_PM */
 
-#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
-
 #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
                          SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
@@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
                .playback = {
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = ATMEL_SSC_RATES,
+                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                       .rate_min = 8000,
+                       .rate_max = 384000,
                        .formats = ATMEL_SSC_FORMATS,},
                .capture = {
                        .channels_min = 1,
                        .channels_max = 2,
-                       .rates = ATMEL_SSC_RATES,
+                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                       .rate_min = 8000,
+                       .rate_max = 384000,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
 };
index b1f08d51149526006021c7314aa4f3e15847de3d..80b153857a88ac25e86d3c4df1fc6ad45f108dc7 100644 (file)
@@ -115,6 +115,7 @@ struct atmel_ssc_info {
        unsigned short rcmr_period;
        struct atmel_pcm_dma_params *dma_params[2];
        struct atmel_ssc_state ssc_state;
+       unsigned long mck_rate;
 };
 
 int atmel_ssc_set_audio(int ssc_id);
index ea9f0e31f9d40d4cf4d8e626371698cb857fcb3a..0bddd929837f4bfd174eff9cde5bc78bfc5611fa 100644 (file)
@@ -141,7 +141,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8770 if SPI_MASTER
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8782
-       select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8804_I2C if I2C
+       select SND_SOC_WM8804_SPI if SPI_MASTER
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
@@ -744,8 +745,19 @@ config SND_SOC_WM8782
        tristate
 
 config SND_SOC_WM8804
-       tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver"
-       depends on SND_SOC_I2C_AND_SPI
+       tristate
+
+config SND_SOC_WM8804_I2C
+       tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C"
+       depends on I2C
+       select SND_SOC_WM8804
+       select REGMAP_I2C
+
+config SND_SOC_WM8804_SPI
+       tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI"
+       depends on SPI_MASTER
+       select SND_SOC_WM8804
+       select REGMAP_SPI
 
 config SND_SOC_WM8900
        tristate
index 69b8666d187a0e8d1e2a532e68e2509acc95da7e..7acb6c174cb48fbd69937878741ee0fc02a4416e 100644 (file)
@@ -145,6 +145,8 @@ snd-soc-wm8770-objs := wm8770.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8782-objs := wm8782.o
 snd-soc-wm8804-objs := wm8804.o
+snd-soc-wm8804-i2c-objs := wm8804-i2c.o
+snd-soc-wm8804-spi-objs := wm8804-spi.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
@@ -323,6 +325,8 @@ obj-$(CONFIG_SND_SOC_WM8770)        += snd-soc-wm8770.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8782)   += snd-soc-wm8782.o
 obj-$(CONFIG_SND_SOC_WM8804)   += snd-soc-wm8804.o
+obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o
+obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
index 70ab35744abadd9970a65a86eaee155f70244db1..7ad8e156e2df9010a6d2fbe2d70bf45358da79af 100644 (file)
@@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap,
                adau1977->dvdd_reg = NULL;
        }
 
-       adau1977->reset_gpio = devm_gpiod_get(dev, "reset");
-       if (IS_ERR(adau1977->reset_gpio)) {
-               ret = PTR_ERR(adau1977->reset_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return PTR_ERR(adau1977->reset_gpio);
-               adau1977->reset_gpio = NULL;
-       }
+       adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                      GPIOD_OUT_LOW);
+       if (IS_ERR(adau1977->reset_gpio))
+               return PTR_ERR(adau1977->reset_gpio);
 
        dev_set_drvdata(dev, adau1977);
 
-       if (adau1977->reset_gpio) {
-               ret = gpiod_direction_output(adau1977->reset_gpio, 0);
-               if (ret)
-                       return ret;
+       if (adau1977->reset_gpio)
                ndelay(100);
-       }
 
        ret = adau1977_power_enable(adau1977);
        if (ret)
index f2b8aad21274aec951fdabc20887b970ef2e1aaa..60598b23034111cb8646b7a8607bca95db79cf01 100644 (file)
@@ -437,20 +437,13 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
        }
 
        /* Reset the Device */
-       cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
-               "reset-gpios");
-       if (IS_ERR(cs35l32->reset_gpio)) {
-               ret = PTR_ERR(cs35l32->reset_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               cs35l32->reset_gpio = NULL;
-       } else {
-               ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
-               if (ret)
-                       return ret;
+       cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+               "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(cs35l32->reset_gpio))
+               return PTR_ERR(cs35l32->reset_gpio);
+
+       if (cs35l32->reset_gpio)
                gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
-       }
 
        /* initialize codec */
        ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
index ce6086835ebdbea24df543cf0f7c271d3bf64a1b..cac48ddf3ba6bb71a20da39945fd6f819b24037a 100644 (file)
@@ -605,21 +605,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
                return ret;
        }
 
-       cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev,
-               "reset-gpios");
-       if (IS_ERR(cs4265->reset_gpio)) {
-               ret = PTR_ERR(cs4265->reset_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               cs4265->reset_gpio = NULL;
-       } else {
-               ret = gpiod_direction_output(cs4265->reset_gpio, 0);
-               if (ret)
-                       return ret;
+       cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+               "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(cs4265->reset_gpio))
+               return PTR_ERR(cs4265->reset_gpio);
+
+       if (cs4265->reset_gpio) {
                mdelay(1);
                gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
-
        }
 
        i2c_set_clientdata(i2c_client, cs4265);
index e9e6efbc21dd527299fb459ec01903fa8c24dae2..bf3e933ee895752352e90f610195f39fc6cc058f 100644 (file)
@@ -26,8 +26,6 @@
 #include <sound/soc-dai.h>
 #include <sound/soc-dapm.h>
 
-#define DRV_NAME "max98357a"
-
 static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
                int cmd, struct snd_soc_dai *dai)
 {
@@ -87,9 +85,9 @@ static struct snd_soc_dai_ops max98357a_dai_ops = {
 };
 
 static struct snd_soc_dai_driver max98357a_dai_driver = {
-       .name = DRV_NAME,
+       .name = "HiFi",
        .playback = {
-               .stream_name    = DRV_NAME "-playback",
+               .stream_name    = "HiFi Playback",
                .formats        = SNDRV_PCM_FMTBIT_S16 |
                                        SNDRV_PCM_FMTBIT_S24 |
                                        SNDRV_PCM_FMTBIT_S32,
@@ -127,7 +125,7 @@ static int max98357a_platform_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_OF
 static const struct of_device_id max98357a_device_id[] = {
-       { .compatible = "maxim," DRV_NAME, },
+       { .compatible = "maxim,max98357a" },
        {}
 };
 MODULE_DEVICE_TABLE(of, max98357a_device_id);
@@ -135,7 +133,7 @@ MODULE_DEVICE_TABLE(of, max98357a_device_id);
 
 static struct platform_driver max98357a_platform_driver = {
        .driver = {
-               .name = DRV_NAME,
+               .name = "max98357a",
                .of_match_table = of_match_ptr(max98357a_device_id),
        },
        .probe  = max98357a_platform_probe,
@@ -145,4 +143,3 @@ module_platform_driver(max98357a_platform_driver);
 
 MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRV_NAME);
index 9974f201a08f44ee25b109c7ff78e13440146c4b..4b5f1fe9be973a2d478fd8ee9c2d1e36ce2d5483 100644 (file)
@@ -54,6 +54,9 @@ struct pcm512x_priv {
        int pll_d;
        int pll_p;
        unsigned long real_pll;
+       unsigned long overclock_pll;
+       unsigned long overclock_dac;
+       unsigned long overclock_dsp;
 };
 
 /*
@@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
        }
 }
 
+static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = pcm512x->overclock_pll;
+       return 0;
+}
+
+static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (codec->dapm.bias_level) {
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       pcm512x->overclock_pll = ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = pcm512x->overclock_dsp;
+       return 0;
+}
+
+static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (codec->dapm.bias_level) {
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       pcm512x->overclock_dsp = ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = pcm512x->overclock_dac;
+       return 0;
+}
+
+static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (codec->dapm.bias_level) {
+       case SND_SOC_BIAS_OFF:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       pcm512x->overclock_dac = ucontrol->value.integer.value[0];
+       return 0;
+}
+
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
 static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
 static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
@@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
 SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus),
 SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf),
 SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds),
+
+SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0,
+              pcm512x_overclock_pll_get, pcm512x_overclock_pll_put),
+SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0,
+              pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put),
+SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0,
+              pcm512x_overclock_dac_get, pcm512x_overclock_dac_put),
 };
 
 static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = {
@@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
        { "OUTR", NULL, "DACR" },
 };
 
+static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x)
+{
+       return 25000000 + 25000000 * pcm512x->overclock_pll / 100;
+}
+
+static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x)
+{
+       return 50000000 + 50000000 * pcm512x->overclock_dsp / 100;
+}
+
+static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x,
+                                    unsigned long rate)
+{
+       return rate + rate * pcm512x->overclock_dac / 100;
+}
+
+static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x)
+{
+       if (!pcm512x->pll_out)
+               return 25000000;
+       return pcm512x_pll_max(pcm512x);
+}
+
+static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x,
+                                       unsigned long dac_rate)
+{
+       /*
+        * If the DAC is not actually overclocked, use the good old
+        * NCP target rate...
+        */
+       if (dac_rate <= 6144000)
+               return 1536000;
+       /*
+        * ...but if the DAC is in fact overclocked, bump the NCP target
+        * rate to get the recommended dividers even when overclocking.
+        */
+       return pcm512x_dac_max(pcm512x, 1536000);
+}
+
 static const u32 pcm512x_dai_rates[] = {
        8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
        88200, 96000, 176400, 192000, 384000,
@@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = {
 static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
                                struct snd_pcm_hw_rule *rule)
 {
+       struct pcm512x_priv *pcm512x = rule->private;
        struct snd_interval ranges[2];
        int frame_size;
 
@@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
                 */
                memset(ranges, 0, sizeof(ranges));
                ranges[0].min = 8000;
-               ranges[0].max = 25000000 / frame_size / 2;
+               ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2;
                ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
                ranges[1].max = 384000;
                break;
@@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
                return snd_pcm_hw_rule_add(substream->runtime, 0,
                                           SNDRV_PCM_HW_PARAM_RATE,
                                           pcm512x_hw_rule_rate,
-                                          NULL,
+                                          pcm512x,
                                           SNDRV_PCM_HW_PARAM_FRAME_BITS,
                                           SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
@@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
                                      unsigned long bclk_rate)
 {
        struct device *dev = dai->dev;
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
        unsigned long sck_rate;
        int pow2;
 
@@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
         * as many factors of 2 as possible, as that makes it easier
         * to find a fast DAC rate
         */
-       pow2 = 1 << fls((25000000 - 16000000) / bclk_rate);
+       pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate);
        for (; pow2; pow2 >>= 1) {
-               sck_rate = rounddown(25000000, bclk_rate * pow2);
+               sck_rate = rounddown(pcm512x_pll_max(pcm512x),
+                                    bclk_rate * pow2);
                if (sck_rate >= 16000000)
                        break;
        }
@@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
                return 0; /* futile, quit early */
 
        /* run DAC no faster than 6144000 Hz */
-       for (dac_rate = rounddown(6144000, osr_rate);
+       for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate);
             dac_rate;
             dac_rate -= osr_rate) {
 
@@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
        osr_rate = 16 * sample_rate;
 
        /* run DSP no faster than 50 MHz */
-       dsp_div = mck_rate > 50000000 ? 2 : 1;
+       dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1;
 
        dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
        if (dac_rate) {
@@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
                dacsrc_rate = pllin_rate;
        } else {
                /* run DAC no faster than 6144000 Hz */
-               unsigned long dac_mul = 6144000 / osr_rate;
+               unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000)
+                       / osr_rate;
                unsigned long sck_mul = sck_rate / osr_rate;
 
                for (; dac_mul; dac_mul--) {
@@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
                dacsrc_rate = sck_rate;
        }
 
+       osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+       if (osr_div > 128) {
+               dev_err(dev, "Failed to find OSR divider\n");
+               return -EINVAL;
+       }
+
        dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
        if (dac_div > 128) {
                dev_err(dev, "Failed to find DAC divider\n");
                return -EINVAL;
        }
+       dac_rate = dacsrc_rate / dac_div;
 
-       ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
-       if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) {
+       ncp_div = DIV_ROUND_CLOSEST(dac_rate,
+                                   pcm512x_ncp_target(pcm512x, dac_rate));
+       if (ncp_div > 128 || dac_rate / ncp_div > 2048000) {
                /* run NCP no faster than 2048000 Hz, but why? */
-               ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
+               ncp_div = DIV_ROUND_UP(dac_rate, 2048000);
                if (ncp_div > 128) {
                        dev_err(dev, "Failed to find NCP divider\n");
                        return -EINVAL;
                }
        }
 
-       osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
-       if (osr_div > 128) {
-               dev_err(dev, "Failed to find OSR divider\n");
-               return -EINVAL;
-       }
-
        idac = mck_rate / (dsp_div * sample_rate);
 
        ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
@@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
                return ret;
        }
 
-       if (sample_rate <= 48000)
+       if (sample_rate <= pcm512x_dac_max(pcm512x, 48000))
                fssp = PCM512x_FSSP_48KHZ;
-       else if (sample_rate <= 96000)
+       else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000))
                fssp = PCM512x_FSSP_96KHZ;
-       else if (sample_rate <= 192000)
+       else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000))
                fssp = PCM512x_FSSP_192KHZ;
        else
                fssp = PCM512x_FSSP_384KHZ;
index 9b541e52da8c77da4134fdf8e0c551d35a2a402b..826037090c8385cf9a2ddaf255052051390f377d 100644 (file)
@@ -395,9 +395,20 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 
        rt286->jack = jack;
 
-       /* Send an initial empty report */
-       snd_soc_jack_report(rt286->jack, 0,
-               SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+       if (jack) {
+               /* enable IRQ */
+               if (rt286->jack->status | SND_JACK_HEADPHONE)
+                       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1");
+               regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
+               /* Send an initial empty report */
+               snd_soc_jack_report(rt286->jack, rt286->jack->status,
+                       SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+       } else {
+               /* disable IRQ */
+               regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
+               snd_soc_dapm_disable_pin(&codec->dapm, "LDO1");
+       }
+       snd_soc_dapm_sync(&codec->dapm);
 
        return 0;
 }
index 21f8e18c13c48d606deb315b6abc82838029e14d..0a67adbcfbc37f394399735e82499f2a6ebdf238 100644 (file)
@@ -1950,17 +1950,20 @@ enum {
 };
 
 enum {
+       RT5670_DMIC1_DISABLED,
        RT5670_DMIC_DATA_GPIO6,
        RT5670_DMIC_DATA_IN2P,
        RT5670_DMIC_DATA_GPIO7,
 };
 
 enum {
+       RT5670_DMIC2_DISABLED,
        RT5670_DMIC_DATA_GPIO8,
        RT5670_DMIC_DATA_IN3N,
 };
 
 enum {
+       RT5670_DMIC3_DISABLED,
        RT5670_DMIC_DATA_GPIO9,
        RT5670_DMIC_DATA_GPIO10,
        RT5670_DMIC_DATA_GPIO5,
index fb9c20eace3fbe9d7bb009862a17c0e8644ec296..c2a6e4091357704b5b0cd714304d8bf862462f5d 100644 (file)
@@ -718,11 +718,24 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
                        RT5677_LDO1_SEL_MASK, 0x0);
                regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
                        RT5677_PWR_LDO1, RT5677_PWR_LDO1);
-               regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
-                       RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
-               regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
-                       RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK,
-                       RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS);
+               switch (rt5677->type) {
+               case RT5677:
+                       regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+                               RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
+                       regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+                               RT5677_PLL2_PR_SRC_MASK |
+                               RT5677_DSP_CLK_SRC_MASK,
+                               RT5677_PLL2_PR_SRC_MCLK2 |
+                               RT5677_DSP_CLK_SRC_BYPASS);
+                       break;
+               case RT5676:
+                       regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+                               RT5677_DSP_CLK_SRC_MASK,
+                               RT5677_DSP_CLK_SRC_BYPASS);
+                       break;
+               default:
+                       break;
+               }
                regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
                regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
                rt5677_set_dsp_mode(codec, true);
@@ -4500,10 +4513,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
        if (!rt5677->dsp_vad_en) {
                regcache_cache_only(rt5677->regmap, true);
                regcache_mark_dirty(rt5677->regmap);
-       }
 
-       if (gpio_is_valid(rt5677->pow_ldo2))
-               gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+               if (gpio_is_valid(rt5677->pow_ldo2))
+                       gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+       }
 
        return 0;
 }
@@ -4512,12 +4525,12 @@ static int rt5677_resume(struct snd_soc_codec *codec)
 {
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
-       if (gpio_is_valid(rt5677->pow_ldo2)) {
-               gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
-               msleep(10);
-       }
-
        if (!rt5677->dsp_vad_en) {
+               if (gpio_is_valid(rt5677->pow_ldo2)) {
+                       gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+                       msleep(10);
+               }
+
                regcache_cache_only(rt5677->regmap, false);
                regcache_sync(rt5677->regmap);
        }
@@ -4733,7 +4746,8 @@ static const struct regmap_config rt5677_regmap = {
 };
 
 static const struct i2c_device_id rt5677_i2c_id[] = {
-       { "rt5677", 0 },
+       { "rt5677", RT5677 },
+       { "rt5676", RT5676 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id);
@@ -4850,6 +4864,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, rt5677);
 
+       rt5677->type = id->driver_data;
+
        if (pdata)
                rt5677->pdata = *pdata;
 
index c0a625f290cc7c25f924321a8eb221dd71547429..07df96b43f5962fb67dca3bcd3bd014c268d6029 100644 (file)
@@ -1665,6 +1665,11 @@ enum {
        RT5677_IRQ_JD3,
 };
 
+enum rt5677_type {
+       RT5677,
+       RT5676,
+};
+
 struct rt5677_priv {
        struct snd_soc_codec *codec;
        struct rt5677_platform_data pdata;
@@ -1681,6 +1686,7 @@ struct rt5677_priv {
        int pll_in;
        int pll_out;
        int pow_ldo2; /* POW_LDO2 pin */
+       enum rt5677_type type;
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip gpio_chip;
 #endif
index 82095d6cd07036d0ad81bf63cdc9e41746c630c3..7947c0ebb1ed88a442ecd8e73338fe858c67819c 100644 (file)
@@ -783,19 +783,21 @@ static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
        snd_soc_write(codec, SN95031_BTNCTRL2, 0x01);
 }
 
-static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack)
+static int sn95031_get_headset_state(struct snd_soc_codec *codec,
+       struct snd_soc_jack *mfld_jack)
 {
-       int micbias = sn95031_get_mic_bias(mfld_jack->codec);
+       int micbias = sn95031_get_mic_bias(codec);
 
        int jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
 
        pr_debug("jack type detected = %d\n", jack_type);
        if (jack_type == SND_JACK_HEADSET)
-               sn95031_enable_jack_btn(mfld_jack->codec);
+               sn95031_enable_jack_btn(codec);
        return jack_type;
 }
 
-void sn95031_jack_detection(struct mfld_jack_data *jack_data)
+void sn95031_jack_detection(struct snd_soc_codec *codec,
+       struct mfld_jack_data *jack_data)
 {
        unsigned int status;
        unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
@@ -809,11 +811,11 @@ void sn95031_jack_detection(struct mfld_jack_data *jack_data)
                status = SND_JACK_HEADSET | SND_JACK_BTN_1;
        } else if (jack_data->intr_id & 0x4) {
                pr_debug("headset or headphones inserted\n");
-               status = sn95031_get_headset_state(jack_data->mfld_jack);
+               status = sn95031_get_headset_state(codec, jack_data->mfld_jack);
        } else if (jack_data->intr_id & 0x8) {
                pr_debug("headset or headphones removed\n");
                status = 0;
-               sn95031_disable_jack_btn(jack_data->mfld_jack->codec);
+               sn95031_disable_jack_btn(codec);
        } else {
                pr_err("unidentified interrupt\n");
                return;
index 20376d234fb83eb26c3bb5eac6c31bc21d5ab24d..7651fe4e6a458907d468675031b7685be4cdf945 100644 (file)
@@ -127,6 +127,7 @@ struct mfld_jack_data {
        struct snd_soc_jack *mfld_jack;
 };
 
-extern void sn95031_jack_detection(struct mfld_jack_data *jack_data);
+extern void sn95031_jack_detection(struct snd_soc_codec *codec,
+       struct mfld_jack_data *jack_data);
 
 #endif
index bda2ee18769ed71e34c96a5a4e93b2621b2dfab2..669e3228241e39d14a2cb009a508cbdb1f6b9fcb 100644 (file)
@@ -1213,27 +1213,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
 #endif
 
        /* GPIOs */
-       sta350->gpiod_nreset = devm_gpiod_get(dev, "reset");
-       if (IS_ERR(sta350->gpiod_nreset)) {
-               ret = PTR_ERR(sta350->gpiod_nreset);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               sta350->gpiod_nreset = NULL;
-       } else {
-               gpiod_direction_output(sta350->gpiod_nreset, 0);
-       }
-
-       sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down");
-       if (IS_ERR(sta350->gpiod_power_down)) {
-               ret = PTR_ERR(sta350->gpiod_power_down);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               sta350->gpiod_power_down = NULL;
-       } else {
-               gpiod_direction_output(sta350->gpiod_power_down, 0);
-       }
+       sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
+                                                      GPIOD_OUT_LOW);
+       if (IS_ERR(sta350->gpiod_nreset))
+               return PTR_ERR(sta350->gpiod_nreset);
+
+       sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down",
+                                                 GPIOD_OUT_LOW);
+       if (IS_ERR(sta350->gpiod_power_down))
+               return PTR_ERR(sta350->gpiod_power_down);
 
        /* regulators */
        for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++)
index ae23acdd2708842b020fca697cdf011d88cff60d..dfb4ff5cc9ea1a697e050cc2d9343dfc9ff58618 100644 (file)
@@ -485,16 +485,9 @@ static int tas2552_probe(struct i2c_client *client,
        if (data == NULL)
                return -ENOMEM;
 
-       data->enable_gpio = devm_gpiod_get(dev, "enable");
-       if (IS_ERR(data->enable_gpio)) {
-               ret = PTR_ERR(data->enable_gpio);
-               if (ret != -ENOENT && ret != -ENOSYS)
-                       return ret;
-
-               data->enable_gpio = NULL;
-       } else {
-               gpiod_direction_output(data->enable_gpio, 0);
-       }
+       data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+       if (IS_ERR(data->enable_gpio))
+               return PTR_ERR(data->enable_gpio);
 
        data->tas2552_client = client;
        data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
new file mode 100644 (file)
index 0000000..5bd4af2
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * wm8804-i2c.c  --  WM8804 S/PDIF transceiver driver - I2C
+ *
+ * Copyright 2015 Cirrus Logic Inc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "wm8804.h"
+
+static int wm8804_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return wm8804_probe(&i2c->dev, regmap);
+}
+
+static int wm8804_i2c_remove(struct i2c_client *i2c)
+{
+       wm8804_remove(&i2c->dev);
+       return 0;
+}
+
+static const struct i2c_device_id wm8804_i2c_id[] = {
+       { "wm8804", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
+
+static const struct of_device_id wm8804_of_match[] = {
+       { .compatible = "wlf,wm8804", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8804_of_match);
+
+static struct i2c_driver wm8804_i2c_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+               .of_match_table = wm8804_of_match,
+       },
+       .probe = wm8804_i2c_probe,
+       .remove = wm8804_i2c_remove,
+       .id_table = wm8804_i2c_id
+};
+
+module_i2c_driver(wm8804_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver - I2C");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c
new file mode 100644 (file)
index 0000000..287e11e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * wm8804-spi.c  --  WM8804 S/PDIF transceiver driver - SPI
+ *
+ * Copyright 2015 Cirrus Logic Inc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "wm8804.h"
+
+static int wm8804_spi_probe(struct spi_device *spi)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return wm8804_probe(&spi->dev, regmap);
+}
+
+static int wm8804_spi_remove(struct spi_device *spi)
+{
+       wm8804_remove(&spi->dev);
+       return 0;
+}
+
+static const struct of_device_id wm8804_of_match[] = {
+       { .compatible = "wlf,wm8804", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8804_of_match);
+
+static struct spi_driver wm8804_spi_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+               .of_match_table = wm8804_of_match,
+       },
+       .probe = wm8804_spi_probe,
+       .remove = wm8804_spi_remove
+};
+
+module_spi_driver(wm8804_spi_driver);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver - SPI");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
index b2b0e68f707e32037fe8dc623aed5be1b2cda73c..1bd4ace295948a4851132e9f75d3e3c12529ea9c 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/i2c.h>
 #include <linux/of_device.h>
-#include <linux/spi/spi.h>
-#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -185,9 +182,9 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg)
        }
 }
 
-static int wm8804_reset(struct snd_soc_codec *codec)
+static int wm8804_reset(struct wm8804_priv *wm8804)
 {
-       return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0);
+       return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0);
 }
 
 static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -518,100 +515,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8804_remove(struct snd_soc_codec *codec)
-{
-       struct wm8804_priv *wm8804;
-       int i;
-
-       wm8804 = snd_soc_codec_get_drvdata(codec);
-
-       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
-               regulator_unregister_notifier(wm8804->supplies[i].consumer,
-                                             &wm8804->disable_nb[i]);
-       return 0;
-}
-
-static int wm8804_probe(struct snd_soc_codec *codec)
-{
-       struct wm8804_priv *wm8804;
-       int i, id1, id2, ret;
-
-       wm8804 = snd_soc_codec_get_drvdata(codec);
-
-       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
-               wm8804->supplies[i].supply = wm8804_supply_names[i];
-
-       ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
-                                wm8804->supplies);
-       if (ret) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               return ret;
-       }
-
-       wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
-       wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
-
-       /* This should really be moved into the regulator core */
-       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
-               ret = regulator_register_notifier(wm8804->supplies[i].consumer,
-                                                 &wm8804->disable_nb[i]);
-               if (ret != 0) {
-                       dev_err(codec->dev,
-                               "Failed to register regulator notifier: %d\n",
-                               ret);
-               }
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
-                                   wm8804->supplies);
-       if (ret) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               return ret;
-       }
-
-       id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
-       if (id1 < 0) {
-               dev_err(codec->dev, "Failed to read device ID: %d\n", id1);
-               ret = id1;
-               goto err_reg_enable;
-       }
-
-       id2 = snd_soc_read(codec, WM8804_DEVID2);
-       if (id2 < 0) {
-               dev_err(codec->dev, "Failed to read device ID: %d\n", id2);
-               ret = id2;
-               goto err_reg_enable;
-       }
-
-       id2 = (id2 << 8) | id1;
-
-       if (id2 != 0x8805) {
-               dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
-               ret = -EINVAL;
-               goto err_reg_enable;
-       }
-
-       ret = snd_soc_read(codec, WM8804_DEVREV);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read device revision: %d\n",
-                       ret);
-               goto err_reg_enable;
-       }
-       dev_info(codec->dev, "revision %c\n", ret + 'A');
-
-       ret = wm8804_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
-               goto err_reg_enable;
-       }
-
-       return 0;
-
-err_reg_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
-       return ret;
-}
-
 static const struct snd_soc_dai_ops wm8804_dai_ops = {
        .hw_params = wm8804_hw_params,
        .set_fmt = wm8804_set_fmt,
@@ -649,8 +552,6 @@ static struct snd_soc_dai_driver wm8804_dai = {
 };
 
 static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
-       .probe = wm8804_probe,
-       .remove = wm8804_remove,
        .set_bias_level = wm8804_set_bias_level,
        .idle_bias_off = true,
 
@@ -658,13 +559,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
        .num_controls = ARRAY_SIZE(wm8804_snd_controls),
 };
 
-static const struct of_device_id wm8804_of_match[] = {
-       { .compatible = "wlf,wm8804", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, wm8804_of_match);
-
-static const struct regmap_config wm8804_regmap_config = {
+const struct regmap_config wm8804_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 
@@ -675,128 +570,110 @@ static const struct regmap_config wm8804_regmap_config = {
        .reg_defaults = wm8804_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
 };
+EXPORT_SYMBOL_GPL(wm8804_regmap_config);
 
-#if defined(CONFIG_SPI_MASTER)
-static int wm8804_spi_probe(struct spi_device *spi)
+int wm8804_probe(struct device *dev, struct regmap *regmap)
 {
        struct wm8804_priv *wm8804;
-       int ret;
+       unsigned int id1, id2;
+       int i, ret;
 
-       wm8804 = devm_kzalloc(&spi->dev, sizeof *wm8804, GFP_KERNEL);
+       wm8804 = devm_kzalloc(dev, sizeof(*wm8804), GFP_KERNEL);
        if (!wm8804)
                return -ENOMEM;
 
-       wm8804->regmap = devm_regmap_init_spi(spi, &wm8804_regmap_config);
-       if (IS_ERR(wm8804->regmap)) {
-               ret = PTR_ERR(wm8804->regmap);
+       dev_set_drvdata(dev, wm8804);
+
+       wm8804->regmap = regmap;
+
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
+               wm8804->supplies[i].supply = wm8804_supply_names[i];
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8804->supplies),
+                                     wm8804->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to request supplies: %d\n", ret);
                return ret;
        }
 
-       spi_set_drvdata(spi, wm8804);
+       wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
+       wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
 
-       ret = snd_soc_register_codec(&spi->dev,
-                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
+               ret = regulator_register_notifier(wm8804->supplies[i].consumer,
+                                                 &wm8804->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
 
-       return ret;
-}
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+                                   wm8804->supplies);
+       if (ret) {
+               dev_err(dev, "Failed to enable supplies: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-static int wm8804_spi_remove(struct spi_device *spi)
-{
-       snd_soc_unregister_codec(&spi->dev);
-       return 0;
-}
+       ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device ID: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-static struct spi_driver wm8804_spi_driver = {
-       .driver = {
-               .name = "wm8804",
-               .owner = THIS_MODULE,
-               .of_match_table = wm8804_of_match,
-       },
-       .probe = wm8804_spi_probe,
-       .remove = wm8804_spi_remove
-};
-#endif
+       ret = regmap_read(regmap, WM8804_DEVID2, &id2);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device ID: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-#if IS_ENABLED(CONFIG_I2C)
-static int wm8804_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
-{
-       struct wm8804_priv *wm8804;
-       int ret;
+       id2 = (id2 << 8) | id1;
 
-       wm8804 = devm_kzalloc(&i2c->dev, sizeof *wm8804, GFP_KERNEL);
-       if (!wm8804)
-               return -ENOMEM;
+       if (id2 != 0x8805) {
+               dev_err(dev, "Invalid device ID: %#x\n", id2);
+               ret = -EINVAL;
+               goto err_reg_enable;
+       }
 
-       wm8804->regmap = devm_regmap_init_i2c(i2c, &wm8804_regmap_config);
-       if (IS_ERR(wm8804->regmap)) {
-               ret = PTR_ERR(wm8804->regmap);
-               return ret;
+       ret = regmap_read(regmap, WM8804_DEVREV, &id1);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_reg_enable;
        }
+       dev_info(dev, "revision %c\n", id1 + 'A');
 
-       i2c_set_clientdata(i2c, wm8804);
+       ret = wm8804_reset(wm8804);
+       if (ret < 0) {
+               dev_err(dev, "Failed to issue reset: %d\n", ret);
+               goto err_reg_enable;
+       }
 
-       ret = snd_soc_register_codec(&i2c->dev,
-                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       return snd_soc_register_codec(dev, &soc_codec_dev_wm8804,
+                                     &wm8804_dai, 1);
+
+err_reg_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wm8804_probe);
 
-static int wm8804_i2c_remove(struct i2c_client *i2c)
+void wm8804_remove(struct device *dev)
 {
-       snd_soc_unregister_codec(&i2c->dev);
-       return 0;
-}
-
-static const struct i2c_device_id wm8804_i2c_id[] = {
-       { "wm8804", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
-
-static struct i2c_driver wm8804_i2c_driver = {
-       .driver = {
-               .name = "wm8804",
-               .owner = THIS_MODULE,
-               .of_match_table = wm8804_of_match,
-       },
-       .probe = wm8804_i2c_probe,
-       .remove = wm8804_i2c_remove,
-       .id_table = wm8804_i2c_id
-};
-#endif
+       struct wm8804_priv *wm8804;
+       int i;
 
-static int __init wm8804_modinit(void)
-{
-       int ret = 0;
+       wm8804 = dev_get_drvdata(dev);
 
-#if IS_ENABLED(CONFIG_I2C)
-       ret = i2c_add_driver(&wm8804_i2c_driver);
-       if (ret) {
-               printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
-                      ret);
-       }
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       ret = spi_register_driver(&wm8804_spi_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
-                      ret);
-       }
-#endif
-       return ret;
-}
-module_init(wm8804_modinit);
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
+               regulator_unregister_notifier(wm8804->supplies[i].consumer,
+                                             &wm8804->disable_nb[i]);
 
-static void __exit wm8804_exit(void)
-{
-#if IS_ENABLED(CONFIG_I2C)
-       i2c_del_driver(&wm8804_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
-       spi_unregister_driver(&wm8804_spi_driver);
-#endif
+       snd_soc_unregister_codec(dev);
 }
-module_exit(wm8804_exit);
+EXPORT_SYMBOL_GPL(wm8804_remove);
 
 MODULE_DESCRIPTION("ASoC WM8804 driver");
 MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
index e72d4f4ba6b154f707086363a8f88081cff9636a..a39a2563dc6704e83835a1a2d6bfceeed4f4171f 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _WM8804_H
 #define _WM8804_H
 
+#include <linux/regmap.h>
+
 /*
  * Register values.
  */
@@ -62,4 +64,9 @@
 #define WM8804_MCLKDIV_256FS                   0
 #define WM8804_MCLKDIV_128FS                   1
 
+extern const struct regmap_config wm8804_regmap_config;
+
+int wm8804_probe(struct device *dev, struct regmap *regmap);
+void wm8804_remove(struct device *dev);
+
 #endif  /* _WM8804_H */
index ff67b334065badc1011807648ac671a4d07765bf..d01c2095452f9a0aaa5a2f1e91d2753fd48b1500 100644 (file)
@@ -420,10 +420,9 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
 
        memcpy(ctl->cache, p, ctl->len);
 
-       if (!ctl->enabled) {
-               ctl->set = 1;
+       ctl->set = 1;
+       if (!ctl->enabled)
                return 0;
-       }
 
        return wm_coeff_write_control(kcontrol, p, ctl->len);
 }
@@ -1185,7 +1184,6 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
        int ret, pos, blocks, type, offset, reg;
        char *file;
        struct wm_adsp_buf *buf;
-       int tmp;
 
        file = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (file == NULL)
@@ -1335,12 +1333,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                        }
                }
 
-               tmp = le32_to_cpu(blk->len) % 4;
-               if (tmp)
-                       pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk);
-               else
-                       pos += le32_to_cpu(blk->len) + sizeof(*blk);
-
+               pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03;
                blocks++;
        }
 
index 2b81ca418d2a67d93087e0acd0fc896cb2478210..3736d9aabc563c9b006c9c00a6abea196e3e5daf 100644 (file)
@@ -1,14 +1,16 @@
 config SND_DAVINCI_SOC
-       tristate "SoC Audio for TI DAVINCI"
+       tristate
        depends on ARCH_DAVINCI
+       select SND_EDMA_SOC
 
 config SND_EDMA_SOC
-       tristate "SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)"
-       depends on SOC_AM33XX || SOC_AM43XX
+       tristate "SoC Audio for Texas Instruments chips using eDMA"
+       depends on SOC_AM33XX || SOC_AM43XX || ARCH_DAVINCI
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M here if you want audio support for TI SoC which uses eDMA.
          The following line of SoCs are supported by this platform driver:
+         - daVinci devices
          - AM335x
          - AM437x/AM438x
 
@@ -17,7 +19,7 @@ config SND_DAVINCI_SOC_I2S
 
 config SND_DAVINCI_SOC_MCASP
        tristate "Multichannel Audio Serial Port (McASP) support"
-       depends on SND_DAVINCI_SOC || SND_OMAP_SOC || SND_EDMA_SOC
+       depends on SND_OMAP_SOC || SND_EDMA_SOC
        help
          Say Y or M here if you want to have support for McASP IP found in
          various Texas Instruments SoCs like:
@@ -45,7 +47,7 @@ config SND_AM33XX_SOC_EVM
 
 config SND_DAVINCI_SOC_EVM
        tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
-       depends on SND_DAVINCI_SOC && I2C
+       depends on SND_EDMA_SOC && I2C
        depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
        select SND_DAVINCI_SOC_GENERIC_EVM
        help
@@ -73,7 +75,7 @@ endchoice
 
 config  SND_DM6467_SOC_EVM
        tristate "SoC Audio support for DaVinci DM6467 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM && I2C
+       depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
        select SND_SOC_SPDIF
 
@@ -82,7 +84,7 @@ config  SND_DM6467_SOC_EVM
 
 config  SND_DA830_SOC_EVM
        tristate "SoC Audio support for DA830/OMAP-L137 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM && I2C
+       depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
 
        help
@@ -91,7 +93,7 @@ config  SND_DA830_SOC_EVM
 
 config  SND_DA850_SOC_EVM
        tristate "SoC Audio support for DA850/OMAP-L138 EVM"
-       depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM && I2C
+       depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
        select SND_DAVINCI_SOC_GENERIC_EVM
        help
          Say Y if you want to add support for SoC audio on TI
index 09bf2ba92d38e3783c8a2b4655c308a54968cc90..f883933c1a194d8a6631b919f91b52cb4c7acf9e 100644 (file)
@@ -1,11 +1,9 @@
 # DAVINCI Platform Support
-snd-soc-davinci-objs := davinci-pcm.o
 snd-soc-edma-objs := edma-pcm.o
 snd-soc-davinci-i2s-objs := davinci-i2s.o
 snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
 snd-soc-davinci-vcif-objs:= davinci-vcif.o
 
-obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
 obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
 obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
 obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
index 15fb28fc8e1b0f2a76d8957f9f85952eb5bb8127..56cb4d95637dda5443ae0766192fedb5217af1df 100644 (file)
@@ -23,8 +23,9 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
-#include "davinci-pcm.h"
+#include "edma-pcm.h"
 #include "davinci-i2s.h"
 
 
@@ -122,7 +123,8 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
 
 struct davinci_mcbsp_dev {
        struct device *dev;
-       struct davinci_pcm_dma_params   dma_params[2];
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       int dma_request[2];
        void __iomem                    *base;
 #define MOD_DSP_A      0
 #define MOD_DSP_B      1
@@ -419,8 +421,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-       struct davinci_pcm_dma_params *dma_params =
-                                       &dev->dma_params[substream->stream];
        struct snd_interval *i = NULL;
        int mcbsp_word_length, master;
        unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
@@ -532,8 +532,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                        return -EINVAL;
                }
        }
-       dma_params->acnt = dma_params->data_type = data_type[fmt];
-       dma_params->fifo_level = 0;
        mcbsp_word_length = asp_word_length[fmt];
 
        switch (master) {
@@ -600,15 +598,6 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int davinci_i2s_startup(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
-{
-       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
-       return 0;
-}
-
 static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
@@ -620,7 +609,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
 #define DAVINCI_I2S_RATES      SNDRV_PCM_RATE_8000_96000
 
 static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
-       .startup        = davinci_i2s_startup,
        .shutdown       = davinci_i2s_shutdown,
        .prepare        = davinci_i2s_prepare,
        .trigger        = davinci_i2s_trigger,
@@ -630,7 +618,18 @@ static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
 
 };
 
+static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+       return 0;
+}
+
 static struct snd_soc_dai_driver davinci_i2s_dai = {
+       .probe = davinci_i2s_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -651,11 +650,9 @@ static const struct snd_soc_component_driver davinci_i2s_component = {
 
 static int davinci_i2s_probe(struct platform_device *pdev)
 {
-       struct snd_platform_data *pdata = pdev->dev.platform_data;
        struct davinci_mcbsp_dev *dev;
        struct resource *mem, *ioarea, *res;
-       enum dma_event_q asp_chan_q = EVENTQ_0;
-       enum dma_event_q ram_chan_q = EVENTQ_1;
+       int *dma;
        int ret;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -676,22 +673,6 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                           GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
-       if (pdata) {
-               dev->enable_channel_combine = pdata->enable_channel_combine;
-               dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size =
-                       pdata->sram_size_playback;
-               dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
-                       pdata->sram_size_capture;
-               dev->clk_input_pin = pdata->clk_input_pin;
-               dev->i2s_accurate_sck = pdata->i2s_accurate_sck;
-               asp_chan_q = pdata->asp_chan_q;
-               ram_chan_q = pdata->ram_chan_q;
-       }
-
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q   = asp_chan_q;
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q   = ram_chan_q;
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q    = asp_chan_q;
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q    = ram_chan_q;
 
        dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk))
@@ -705,10 +686,10 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                goto err_release_clk;
        }
 
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
+       dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
            (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
 
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
+       dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
            (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
 
        /* first TX, then RX */
@@ -718,7 +699,9 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                ret = -ENXIO;
                goto err_release_clk;
        }
-       dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start;
+       dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
+       *dma = res->start;
+       dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = dma;
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!res) {
@@ -726,9 +709,11 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                ret = -ENXIO;
                goto err_release_clk;
        }
-       dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
-       dev->dev = &pdev->dev;
+       dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE];
+       *dma = res->start;
+       dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = dma;
 
+       dev->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, dev);
 
        ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
@@ -736,7 +721,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        if (ret != 0)
                goto err_release_clk;
 
-       ret = davinci_soc_platform_register(&pdev->dev);
+       ret = edma_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
                goto err_unregister_component;
index de3b155a50116f4e533c8f22e0fc6b933e8040ae..0c882995a3575a05841de42fae80015b9b7611a5 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
+#include <linux/platform_data/davinci_asp.h>
 
 #include <sound/asoundef.h>
 #include <sound/core.h>
@@ -36,7 +37,6 @@
 #include <sound/dmaengine_pcm.h>
 #include <sound/omap-pcm.h>
 
-#include "davinci-pcm.h"
 #include "edma-pcm.h"
 #include "davinci-mcasp.h"
 
@@ -65,7 +65,6 @@ struct davinci_mcasp_context {
 };
 
 struct davinci_mcasp {
-       struct davinci_pcm_dma_params dma_params[2];
        struct snd_dmaengine_dai_dma_data dma_data[2];
        void __iomem *base;
        u32 fifo_base;
@@ -82,6 +81,7 @@ struct davinci_mcasp {
        u16     bclk_lrclk_ratio;
        int     streams;
        u32     irq_request[2];
+       int     dma_request[2];
 
        int     sysclk_freq;
        bool    bclk_master;
@@ -441,6 +441,18 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
                mcasp->bclk_master = 1;
                break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               /* codec is clock slave and frame master */
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+               mcasp->bclk_master = 1;
+               break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
@@ -631,7 +643,6 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
 static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                                 int period_words, int channels)
 {
-       struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream];
        struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
        int i;
        u8 tx_ser = 0;
@@ -699,10 +710,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                         * For example if three serializers are enabled the DMA
                         * need to transfer three words per DMA request.
                         */
-                       dma_params->fifo_level = active_serializers;
                        dma_data->maxburst = active_serializers;
                } else {
-                       dma_params->fifo_level = 0;
                        dma_data->maxburst = 0;
                }
                return 0;
@@ -734,7 +743,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
        /* Configure the burst size for platform drivers */
        if (numevt == 1)
                numevt = 0;
-       dma_params->fifo_level = numevt;
        dma_data->maxburst = numevt;
 
        return 0;
@@ -860,8 +868,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_soc_dai *cpu_dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct davinci_pcm_dma_params *dma_params =
-                                       &mcasp->dma_params[substream->stream];
        int word_length;
        int channels = params_channels(params);
        int period_size = params_period_size(params);
@@ -902,31 +908,26 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U8:
        case SNDRV_PCM_FORMAT_S8:
-               dma_params->data_type = 1;
                word_length = 8;
                break;
 
        case SNDRV_PCM_FORMAT_U16_LE:
        case SNDRV_PCM_FORMAT_S16_LE:
-               dma_params->data_type = 2;
                word_length = 16;
                break;
 
        case SNDRV_PCM_FORMAT_U24_3LE:
        case SNDRV_PCM_FORMAT_S24_3LE:
-               dma_params->data_type = 3;
                word_length = 24;
                break;
 
        case SNDRV_PCM_FORMAT_U24_LE:
        case SNDRV_PCM_FORMAT_S24_LE:
-               dma_params->data_type = 4;
                word_length = 24;
                break;
 
        case SNDRV_PCM_FORMAT_U32_LE:
        case SNDRV_PCM_FORMAT_S32_LE:
-               dma_params->data_type = 4;
                word_length = 32;
                break;
 
@@ -935,11 +936,6 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level)
-               dma_params->acnt = 4;
-       else
-               dma_params->acnt = dma_params->data_type;
-
        davinci_config_channel_size(mcasp, word_length);
 
        if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
@@ -1043,17 +1039,8 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
-       if (mcasp->version >= MCASP_VERSION_3) {
-               /* Using dmaengine PCM */
-               dai->playback_dma_data =
-                               &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-               dai->capture_dma_data =
-                               &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-       } else {
-               /* Using davinci-pcm */
-               dai->playback_dma_data = mcasp->dma_params;
-               dai->capture_dma_data = mcasp->dma_params;
-       }
+       dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
 
        return 0;
 }
@@ -1172,28 +1159,24 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
 static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
        .tx_dma_offset = 0x400,
        .rx_dma_offset = 0x400,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_1,
 };
 
 static struct davinci_mcasp_pdata da830_mcasp_pdata = {
        .tx_dma_offset = 0x2000,
        .rx_dma_offset = 0x2000,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_2,
 };
 
 static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
        .tx_dma_offset = 0,
        .rx_dma_offset = 0,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_3,
 };
 
 static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
        .tx_dma_offset = 0x200,
        .rx_dma_offset = 0x284,
-       .asp_chan_q = EVENTQ_0,
        .version = MCASP_VERSION_4,
 };
 
@@ -1370,12 +1353,12 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
 
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
-       struct davinci_pcm_dma_params *dma_params;
        struct snd_dmaengine_dai_dma_data *dma_data;
        struct resource *mem, *ioarea, *res, *dat;
        struct davinci_mcasp_pdata *pdata;
        struct davinci_mcasp *mcasp;
        char *irq_name;
+       int *dma;
        int irq;
        int ret;
 
@@ -1509,59 +1492,45 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (dat)
                mcasp->dat_port = true;
 
-       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
        dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
-       dma_params->asp_chan_q = pdata->asp_chan_q;
-       dma_params->ram_chan_q = pdata->ram_chan_q;
-       dma_params->sram_pool = pdata->sram_pool;
-       dma_params->sram_size = pdata->sram_size_playback;
        if (dat)
-               dma_params->dma_addr = dat->start;
+               dma_data->addr = dat->start;
        else
-               dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
-
-       /* Unconditional dmaengine stuff */
-       dma_data->addr = dma_params->dma_addr;
+               dma_data->addr = mem->start + pdata->tx_dma_offset;
 
+       dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK];
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (res)
-               dma_params->channel = res->start;
+               *dma = res->start;
        else
-               dma_params->channel = pdata->tx_dma_channel;
+               *dma = pdata->tx_dma_channel;
 
        /* dmaengine filter data for DT and non-DT boot */
        if (pdev->dev.of_node)
                dma_data->filter_data = "tx";
        else
-               dma_data->filter_data = &dma_params->channel;
+               dma_data->filter_data = dma;
 
        /* RX is not valid in DIT mode */
        if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
-               dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
                dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-               dma_params->asp_chan_q = pdata->asp_chan_q;
-               dma_params->ram_chan_q = pdata->ram_chan_q;
-               dma_params->sram_pool = pdata->sram_pool;
-               dma_params->sram_size = pdata->sram_size_capture;
                if (dat)
-                       dma_params->dma_addr = dat->start;
+                       dma_data->addr = dat->start;
                else
-                       dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
-
-               /* Unconditional dmaengine stuff */
-               dma_data->addr = dma_params->dma_addr;
+                       dma_data->addr = mem->start + pdata->rx_dma_offset;
 
+               dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE];
                res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
                if (res)
-                       dma_params->channel = res->start;
+                       *dma = res->start;
                else
-                       dma_params->channel = pdata->rx_dma_channel;
+                       *dma = pdata->rx_dma_channel;
 
                /* dmaengine filter data for DT and non-DT boot */
                if (pdev->dev.of_node)
                        dma_data->filter_data = "rx";
                else
-                       dma_data->filter_data = &dma_params->channel;
+                       dma_data->filter_data = dma;
        }
 
        if (mcasp->version < MCASP_VERSION_3) {
@@ -1584,17 +1553,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                goto err;
 
        switch (mcasp->version) {
-#if IS_BUILTIN(CONFIG_SND_DAVINCI_SOC) || \
-       (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
-        IS_MODULE(CONFIG_SND_DAVINCI_SOC))
-       case MCASP_VERSION_1:
-       case MCASP_VERSION_2:
-               ret = davinci_soc_platform_register(&pdev->dev);
-               break;
-#endif
 #if IS_BUILTIN(CONFIG_SND_EDMA_SOC) || \
        (IS_MODULE(CONFIG_SND_DAVINCI_SOC_MCASP) && \
         IS_MODULE(CONFIG_SND_EDMA_SOC))
+       case MCASP_VERSION_1:
+       case MCASP_VERSION_2:
        case MCASP_VERSION_3:
                ret = edma_pcm_platform_register(&pdev->dev);
                break;
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
deleted file mode 100644 (file)
index 7809e9d..0000000
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * ALSA PCM interface for the TI DAVINCI processor
- *
- * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/genalloc.h>
-#include <linux/platform_data/edma.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-
-#include "davinci-pcm.h"
-
-#ifdef DEBUG
-static void print_buf_info(int slot, char *name)
-{
-       struct edmacc_param p;
-       if (slot < 0)
-               return;
-       edma_read_slot(slot, &p);
-       printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n",
-                       name, slot, p.opt, p.src, p.a_b_cnt, p.dst);
-       printk(KERN_DEBUG "    src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n",
-                       p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt);
-}
-#else
-static void print_buf_info(int slot, char *name)
-{
-}
-#endif
-
-static struct snd_pcm_hardware pcm_hardware_playback = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
-                SNDRV_PCM_INFO_BATCH),
-       .buffer_bytes_max = 128 * 1024,
-       .period_bytes_min = 32,
-       .period_bytes_max = 8 * 1024,
-       .periods_min = 16,
-       .periods_max = 255,
-       .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware pcm_hardware_capture = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE |
-                SNDRV_PCM_INFO_BATCH),
-       .buffer_bytes_max = 128 * 1024,
-       .period_bytes_min = 32,
-       .period_bytes_max = 8 * 1024,
-       .periods_min = 16,
-       .periods_max = 255,
-       .fifo_size = 0,
-};
-
-/*
- * How ping/pong works....
- *
- * Playback:
- * ram_params - copys 2*ping_size from start of SDRAM to iram,
- *     links to ram_link2
- * ram_link2 - copys rest of SDRAM to iram in ping_size units,
- *     links to ram_link
- * ram_link - copys entire SDRAM to iram in ping_size uints,
- *     links to self
- *
- * asp_params - same as asp_link[0]
- * asp_link[0] - copys from lower half of iram to asp port
- *     links to asp_link[1], triggers iram copy event on completion
- * asp_link[1] - copys from upper half of iram to asp port
- *     links to asp_link[0], triggers iram copy event on completion
- *     triggers interrupt only needed to let upper SOC levels update position
- *     in stream on completion
- *
- * When playback is started:
- *     ram_params started
- *     asp_params started
- *
- * Capture:
- * ram_params - same as ram_link,
- *     links to ram_link
- * ram_link - same as playback
- *     links to self
- *
- * asp_params - same as playback
- * asp_link[0] - same as playback
- * asp_link[1] - same as playback
- *
- * When capture is started:
- *     asp_params started
- */
-struct davinci_runtime_data {
-       spinlock_t lock;
-       int period;             /* current DMA period */
-       int asp_channel;        /* Master DMA channel */
-       int asp_link[2];        /* asp parameter link channel, ping/pong */
-       struct davinci_pcm_dma_params *params;  /* DMA params */
-       int ram_channel;
-       int ram_link;
-       int ram_link2;
-       struct edmacc_param asp_params;
-       struct edmacc_param ram_params;
-};
-
-static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       prtd->period++;
-       if (unlikely(prtd->period >= runtime->periods))
-               prtd->period = 0;
-}
-
-static void davinci_pcm_period_reset(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-
-       prtd->period = 0;
-}
-/*
- * Not used with ping/pong
- */
-static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int period_size;
-       unsigned int dma_offset;
-       dma_addr_t dma_pos;
-       dma_addr_t src, dst;
-       unsigned short src_bidx, dst_bidx;
-       unsigned short src_cidx, dst_cidx;
-       unsigned int data_type;
-       unsigned short acnt;
-       unsigned int count;
-       unsigned int fifo_level;
-
-       period_size = snd_pcm_lib_period_bytes(substream);
-       dma_offset = prtd->period * period_size;
-       dma_pos = runtime->dma_addr + dma_offset;
-       fifo_level = prtd->params->fifo_level;
-
-       pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
-               "dma_ptr = %x period_size=%x\n", prtd->asp_link[0], dma_pos,
-               period_size);
-
-       data_type = prtd->params->data_type;
-       count = period_size / data_type;
-       if (fifo_level)
-               count /= fifo_level;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               src = dma_pos;
-               dst = prtd->params->dma_addr;
-               src_bidx = data_type;
-               dst_bidx = 4;
-               src_cidx = data_type * fifo_level;
-               dst_cidx = 0;
-       } else {
-               src = prtd->params->dma_addr;
-               dst = dma_pos;
-               src_bidx = 0;
-               dst_bidx = data_type;
-               src_cidx = 0;
-               dst_cidx = data_type * fifo_level;
-       }
-
-       acnt = prtd->params->acnt;
-       edma_set_src(prtd->asp_link[0], src, INCR, W8BIT);
-       edma_set_dest(prtd->asp_link[0], dst, INCR, W8BIT);
-
-       edma_set_src_index(prtd->asp_link[0], src_bidx, src_cidx);
-       edma_set_dest_index(prtd->asp_link[0], dst_bidx, dst_cidx);
-
-       if (!fifo_level)
-               edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
-                                                       ASYNC);
-       else
-               edma_set_transfer_params(prtd->asp_link[0], acnt,
-                                               fifo_level,
-                                               count, fifo_level,
-                                               ABSYNC);
-}
-
-static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
-{
-       struct snd_pcm_substream *substream = data;
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-
-       print_buf_info(prtd->ram_channel, "i ram_channel");
-       pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status);
-
-       if (unlikely(ch_status != EDMA_DMA_COMPLETE))
-               return;
-
-       if (snd_pcm_running(substream)) {
-               spin_lock(&prtd->lock);
-               if (prtd->ram_channel < 0) {
-                       /* No ping/pong must fix up link dma data*/
-                       davinci_pcm_enqueue_dma(substream);
-               }
-               davinci_pcm_period_elapsed(substream);
-               spin_unlock(&prtd->lock);
-               snd_pcm_period_elapsed(substream);
-       }
-}
-
-#ifdef CONFIG_GENERIC_ALLOCATOR
-static int allocate_sram(struct snd_pcm_substream *substream,
-               struct gen_pool *sram_pool, unsigned size,
-               struct snd_pcm_hardware *ppcm)
-{
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       struct snd_dma_buffer *iram_dma = NULL;
-       dma_addr_t iram_phys = 0;
-       void *iram_virt = NULL;
-
-       if (buf->private_data || !size)
-               return 0;
-
-       ppcm->period_bytes_max = size;
-       iram_virt = gen_pool_dma_alloc(sram_pool, size, &iram_phys);
-       if (!iram_virt)
-               goto exit1;
-       iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL);
-       if (!iram_dma)
-               goto exit2;
-       iram_dma->area = iram_virt;
-       iram_dma->addr = iram_phys;
-       memset(iram_dma->area, 0, size);
-       iram_dma->bytes = size;
-       buf->private_data = iram_dma;
-       return 0;
-exit2:
-       if (iram_virt)
-               gen_pool_free(sram_pool, (unsigned)iram_virt, size);
-exit1:
-       return -ENOMEM;
-}
-
-static void davinci_free_sram(struct snd_pcm_substream *substream,
-                             struct snd_dma_buffer *iram_dma)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct gen_pool *sram_pool = prtd->params->sram_pool;
-
-       gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes);
-}
-#else
-static int allocate_sram(struct snd_pcm_substream *substream,
-               struct gen_pool *sram_pool, unsigned size,
-               struct snd_pcm_hardware *ppcm)
-{
-       return 0;
-}
-
-static void davinci_free_sram(struct snd_pcm_substream *substream,
-                             struct snd_dma_buffer *iram_dma)
-{
-}
-#endif
-
-/*
- * Only used with ping/pong.
- * This is called after runtime->dma_addr, period_bytes and data_type are valid
- */
-static int ping_pong_dma_setup(struct snd_pcm_substream *substream)
-{
-       unsigned short ram_src_cidx, ram_dst_cidx;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd = runtime->private_data;
-       struct snd_dma_buffer *iram_dma =
-               (struct snd_dma_buffer *)substream->dma_buffer.private_data;
-       struct davinci_pcm_dma_params *params = prtd->params;
-       unsigned int data_type = params->data_type;
-       unsigned int acnt = params->acnt;
-       /* divide by 2 for ping/pong */
-       unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
-       unsigned int fifo_level = prtd->params->fifo_level;
-       unsigned int count;
-       if ((data_type == 0) || (data_type > 4)) {
-               printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type);
-               return -EINVAL;
-       }
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
-               ram_src_cidx = ping_size;
-               ram_dst_cidx = -ping_size;
-               edma_set_src(prtd->asp_link[1], asp_src_pong, INCR, W8BIT);
-
-               edma_set_src_index(prtd->asp_link[0], data_type,
-                               data_type * fifo_level);
-               edma_set_src_index(prtd->asp_link[1], data_type,
-                               data_type * fifo_level);
-
-               edma_set_src(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
-       } else {
-               dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
-               ram_src_cidx = -ping_size;
-               ram_dst_cidx = ping_size;
-               edma_set_dest(prtd->asp_link[1], asp_dst_pong, INCR, W8BIT);
-
-               edma_set_dest_index(prtd->asp_link[0], data_type,
-                               data_type * fifo_level);
-               edma_set_dest_index(prtd->asp_link[1], data_type,
-                               data_type * fifo_level);
-
-               edma_set_dest(prtd->ram_link, runtime->dma_addr, INCR, W32BIT);
-       }
-
-       if (!fifo_level) {
-               count = ping_size / data_type;
-               edma_set_transfer_params(prtd->asp_link[0], acnt, count,
-                               1, 0, ASYNC);
-               edma_set_transfer_params(prtd->asp_link[1], acnt, count,
-                               1, 0, ASYNC);
-       } else {
-               count = ping_size / (data_type * fifo_level);
-               edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
-                               count, fifo_level, ABSYNC);
-               edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level,
-                               count, fifo_level, ABSYNC);
-       }
-
-       edma_set_src_index(prtd->ram_link, ping_size, ram_src_cidx);
-       edma_set_dest_index(prtd->ram_link, ping_size, ram_dst_cidx);
-       edma_set_transfer_params(prtd->ram_link, ping_size, 2,
-                       runtime->periods, 2, ASYNC);
-
-       /* init master params */
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       edma_read_slot(prtd->ram_link, &prtd->ram_params);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               struct edmacc_param p_ram;
-               /* Copy entire iram buffer before playback started */
-               prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1);
-               /* 0 dst_bidx */
-               prtd->ram_params.src_dst_bidx = (ping_size << 1);
-               /* 0 dst_cidx */
-               prtd->ram_params.src_dst_cidx = (ping_size << 1);
-               prtd->ram_params.ccnt = 1;
-
-               /* Skip 1st period */
-               edma_read_slot(prtd->ram_link, &p_ram);
-               p_ram.src += (ping_size << 1);
-               p_ram.ccnt -= 1;
-               edma_write_slot(prtd->ram_link2, &p_ram);
-               /*
-                * When 1st started, ram -> iram dma channel will fill the
-                * entire iram.  Then, whenever a ping/pong asp buffer finishes,
-                * 1/2 iram will be filled.
-                */
-               prtd->ram_params.link_bcntrld =
-                       EDMA_CHAN_SLOT(prtd->ram_link2) << 5;
-       }
-       return 0;
-}
-
-/* 1 asp tx or rx channel using 2 parameter channels
- * 1 ram to/from iram channel using 1 parameter channel
- *
- * Playback
- * ram copy channel kicks off first,
- * 1st ram copy of entire iram buffer completion kicks off asp channel
- * asp tcc always kicks off ram copy of 1/2 iram buffer
- *
- * Record
- * asp channel starts, tcc kicks off ram copy
- */
-static int request_ping_pong(struct snd_pcm_substream *substream,
-               struct davinci_runtime_data *prtd,
-               struct snd_dma_buffer *iram_dma)
-{
-       dma_addr_t asp_src_ping;
-       dma_addr_t asp_dst_ping;
-       int ret;
-       struct davinci_pcm_dma_params *params = prtd->params;
-
-       /* Request ram master channel */
-       ret = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
-                                 davinci_pcm_dma_irq, substream,
-                                 prtd->params->ram_chan_q);
-       if (ret < 0)
-               goto exit1;
-
-       /* Request ram link channel */
-       ret = prtd->ram_link = edma_alloc_slot(
-                       EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
-       if (ret < 0)
-               goto exit2;
-
-       ret = prtd->asp_link[1] = edma_alloc_slot(
-                       EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
-       if (ret < 0)
-               goto exit3;
-
-       prtd->ram_link2 = -1;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               ret = prtd->ram_link2 = edma_alloc_slot(
-                       EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
-               if (ret < 0)
-                       goto exit4;
-       }
-       /* circle ping-pong buffers */
-       edma_link(prtd->asp_link[0], prtd->asp_link[1]);
-       edma_link(prtd->asp_link[1], prtd->asp_link[0]);
-       /* circle ram buffers */
-       edma_link(prtd->ram_link, prtd->ram_link);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               asp_src_ping = iram_dma->addr;
-               asp_dst_ping = params->dma_addr;        /* fifo */
-       } else {
-               asp_src_ping = params->dma_addr;        /* fifo */
-               asp_dst_ping = iram_dma->addr;
-       }
-       /* ping */
-       edma_set_src(prtd->asp_link[0], asp_src_ping, INCR, W16BIT);
-       edma_set_dest(prtd->asp_link[0], asp_dst_ping, INCR, W16BIT);
-       edma_set_src_index(prtd->asp_link[0], 0, 0);
-       edma_set_dest_index(prtd->asp_link[0], 0, 0);
-
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
-       prtd->asp_params.opt |= TCCHEN |
-               EDMA_TCC(prtd->ram_channel & 0x3f);
-       edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
-
-       /* pong */
-       edma_set_src(prtd->asp_link[1], asp_src_ping, INCR, W16BIT);
-       edma_set_dest(prtd->asp_link[1], asp_dst_ping, INCR, W16BIT);
-       edma_set_src_index(prtd->asp_link[1], 0, 0);
-       edma_set_dest_index(prtd->asp_link[1], 0, 0);
-
-       edma_read_slot(prtd->asp_link[1], &prtd->asp_params);
-       prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
-       /* interrupt after every pong completion */
-       prtd->asp_params.opt |= TCINTEN | TCCHEN |
-               EDMA_TCC(prtd->ram_channel & 0x3f);
-       edma_write_slot(prtd->asp_link[1], &prtd->asp_params);
-
-       /* ram */
-       edma_set_src(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
-       edma_set_dest(prtd->ram_link, iram_dma->addr, INCR, W32BIT);
-       pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u,"
-               "for asp:%u %u %u\n", __func__,
-               prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
-               prtd->asp_channel, prtd->asp_link[0],
-               prtd->asp_link[1]);
-       return 0;
-exit4:
-       edma_free_channel(prtd->asp_link[1]);
-       prtd->asp_link[1] = -1;
-exit3:
-       edma_free_channel(prtd->ram_link);
-       prtd->ram_link = -1;
-exit2:
-       edma_free_channel(prtd->ram_channel);
-       prtd->ram_channel = -1;
-exit1:
-       return ret;
-}
-
-static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
-{
-       struct snd_dma_buffer *iram_dma;
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       struct davinci_pcm_dma_params *params = prtd->params;
-       int ret;
-
-       if (!params)
-               return -ENODEV;
-
-       /* Request asp master DMA channel */
-       ret = prtd->asp_channel = edma_alloc_channel(params->channel,
-                       davinci_pcm_dma_irq, substream,
-                       prtd->params->asp_chan_q);
-       if (ret < 0)
-               goto exit1;
-
-       /* Request asp link channels */
-       ret = prtd->asp_link[0] = edma_alloc_slot(
-                       EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
-       if (ret < 0)
-               goto exit2;
-
-       iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data;
-       if (iram_dma) {
-               if (request_ping_pong(substream, prtd, iram_dma) == 0)
-                       return 0;
-               printk(KERN_WARNING "%s: dma channel allocation failed,"
-                               "not using sram\n", __func__);
-       }
-
-       /* Issue transfer completion IRQ when the channel completes a
-        * transfer, then always reload from the same slot (by a kind
-        * of loopback link).  The completion IRQ handler will update
-        * the reload slot with a new buffer.
-        *
-        * REVISIT save p_ram here after setting up everything except
-        * the buffer and its length (ccnt) ... use it as a template
-        * so davinci_pcm_enqueue_dma() takes less time in IRQ.
-        */
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       prtd->asp_params.opt |= TCINTEN |
-               EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
-       prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5;
-       edma_write_slot(prtd->asp_link[0], &prtd->asp_params);
-       return 0;
-exit2:
-       edma_free_channel(prtd->asp_channel);
-       prtd->asp_channel = -1;
-exit1:
-       return ret;
-}
-
-static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       spin_lock(&prtd->lock);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               edma_start(prtd->asp_channel);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-                   prtd->ram_channel >= 0) {
-                       /* copy 1st iram buffer */
-                       edma_start(prtd->ram_channel);
-               }
-               break;
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               edma_resume(prtd->asp_channel);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               edma_pause(prtd->asp_channel);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       spin_unlock(&prtd->lock);
-
-       return ret;
-}
-
-static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct davinci_runtime_data *prtd = substream->runtime->private_data;
-
-       davinci_pcm_period_reset(substream);
-       if (prtd->ram_channel >= 0) {
-               int ret = ping_pong_dma_setup(substream);
-               if (ret < 0)
-                       return ret;
-
-               edma_write_slot(prtd->ram_channel, &prtd->ram_params);
-               edma_write_slot(prtd->asp_channel, &prtd->asp_params);
-
-               print_buf_info(prtd->ram_channel, "ram_channel");
-               print_buf_info(prtd->ram_link, "ram_link");
-               print_buf_info(prtd->ram_link2, "ram_link2");
-               print_buf_info(prtd->asp_channel, "asp_channel");
-               print_buf_info(prtd->asp_link[0], "asp_link[0]");
-               print_buf_info(prtd->asp_link[1], "asp_link[1]");
-
-               /*
-                * There is a phase offset of 2 periods between the position
-                * used by dma setup and the position reported in the pointer
-                * function.
-                *
-                * The phase offset, when not using ping-pong buffers, is due to
-                * the two consecutive calls to davinci_pcm_enqueue_dma() below.
-                *
-                * Whereas here, with ping-pong buffers, the phase is due to
-                * there being an entire buffer transfer complete before the
-                * first dma completion event triggers davinci_pcm_dma_irq().
-                */
-               davinci_pcm_period_elapsed(substream);
-               davinci_pcm_period_elapsed(substream);
-
-               return 0;
-       }
-       davinci_pcm_enqueue_dma(substream);
-       davinci_pcm_period_elapsed(substream);
-
-       /* Copy self-linked parameter RAM entry into master channel */
-       edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
-       edma_write_slot(prtd->asp_channel, &prtd->asp_params);
-       davinci_pcm_enqueue_dma(substream);
-       davinci_pcm_period_elapsed(substream);
-
-       return 0;
-}
-
-static snd_pcm_uframes_t
-davinci_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd = runtime->private_data;
-       unsigned int offset;
-       int asp_count;
-       unsigned int period_size = snd_pcm_lib_period_bytes(substream);
-
-       /*
-        * There is a phase offset of 2 periods between the position used by dma
-        * setup and the position reported in the pointer function. Either +2 in
-        * the dma setup or -2 here in the pointer function (with wrapping,
-        * both) accounts for this offset -- choose the latter since it makes
-        * the first-time setup clearer.
-        */
-       spin_lock(&prtd->lock);
-       asp_count = prtd->period - 2;
-       spin_unlock(&prtd->lock);
-
-       if (asp_count < 0)
-               asp_count += runtime->periods;
-       asp_count *= period_size;
-
-       offset = bytes_to_frames(runtime, asp_count);
-       if (offset >= runtime->buffer_size)
-               offset = 0;
-
-       return offset;
-}
-
-static int davinci_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd;
-       struct snd_pcm_hardware *ppcm;
-       int ret = 0;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct davinci_pcm_dma_params *pa;
-       struct davinci_pcm_dma_params *params;
-
-       pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       if (!pa)
-               return -ENODEV;
-       params = &pa[substream->stream];
-
-       ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                       &pcm_hardware_playback : &pcm_hardware_capture;
-       allocate_sram(substream, params->sram_pool, params->sram_size, ppcm);
-       snd_soc_set_runtime_hwparams(substream, ppcm);
-       /* ensure that buffer size is a multiple of period size */
-       ret = snd_pcm_hw_constraint_integer(runtime,
-                                               SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               return ret;
-
-       prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
-       if (prtd == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&prtd->lock);
-       prtd->params = params;
-       prtd->asp_channel = -1;
-       prtd->asp_link[0] = prtd->asp_link[1] = -1;
-       prtd->ram_channel = -1;
-       prtd->ram_link = -1;
-       prtd->ram_link2 = -1;
-
-       runtime->private_data = prtd;
-
-       ret = davinci_pcm_dma_request(substream);
-       if (ret) {
-               printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n");
-               kfree(prtd);
-       }
-
-       return ret;
-}
-
-static int davinci_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct davinci_runtime_data *prtd = runtime->private_data;
-
-       if (prtd->ram_channel >= 0)
-               edma_stop(prtd->ram_channel);
-       if (prtd->asp_channel >= 0)
-               edma_stop(prtd->asp_channel);
-       if (prtd->asp_link[0] >= 0)
-               edma_unlink(prtd->asp_link[0]);
-       if (prtd->asp_link[1] >= 0)
-               edma_unlink(prtd->asp_link[1]);
-       if (prtd->ram_link >= 0)
-               edma_unlink(prtd->ram_link);
-
-       if (prtd->asp_link[0] >= 0)
-               edma_free_slot(prtd->asp_link[0]);
-       if (prtd->asp_link[1] >= 0)
-               edma_free_slot(prtd->asp_link[1]);
-       if (prtd->asp_channel >= 0)
-               edma_free_channel(prtd->asp_channel);
-       if (prtd->ram_link >= 0)
-               edma_free_slot(prtd->ram_link);
-       if (prtd->ram_link2 >= 0)
-               edma_free_slot(prtd->ram_link2);
-       if (prtd->ram_channel >= 0)
-               edma_free_channel(prtd->ram_channel);
-
-       kfree(prtd);
-
-       return 0;
-}
-
-static int davinci_pcm_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *hw_params)
-{
-       return snd_pcm_lib_malloc_pages(substream,
-                                       params_buffer_bytes(hw_params));
-}
-
-static int davinci_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       return snd_pcm_lib_free_pages(substream);
-}
-
-static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
-                           struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops davinci_pcm_ops = {
-       .open =         davinci_pcm_open,
-       .close =        davinci_pcm_close,
-       .ioctl =        snd_pcm_lib_ioctl,
-       .hw_params =    davinci_pcm_hw_params,
-       .hw_free =      davinci_pcm_hw_free,
-       .prepare =      davinci_pcm_prepare,
-       .trigger =      davinci_pcm_trigger,
-       .pointer =      davinci_pcm_pointer,
-       .mmap =         davinci_pcm_mmap,
-};
-
-static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
-               size_t size)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-
-       pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, "
-               "size=%d\n", (void *) buf->area, (void *) buf->addr, size);
-
-       if (!buf->area)
-               return -ENOMEM;
-
-       buf->bytes = size;
-       return 0;
-}
-
-static void davinci_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               struct snd_dma_buffer *iram_dma;
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-               iram_dma = buf->private_data;
-               if (iram_dma) {
-                       davinci_free_sram(substream, iram_dma);
-                       kfree(iram_dma);
-               }
-       }
-}
-
-static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret;
-
-       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
-       if (ret)
-               return ret;
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = davinci_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK,
-                       pcm_hardware_playback.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = davinci_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE,
-                       pcm_hardware_capture.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_platform_driver davinci_soc_platform = {
-       .ops =          &davinci_pcm_ops,
-       .pcm_new =      davinci_pcm_new,
-       .pcm_free =     davinci_pcm_free,
-};
-
-int davinci_soc_platform_register(struct device *dev)
-{
-       return devm_snd_soc_register_platform(dev, &davinci_soc_platform);
-}
-EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
-
-MODULE_AUTHOR("Vladimir Barinov");
-MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
deleted file mode 100644 (file)
index 0fe2346..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * ALSA PCM interface for the TI DAVINCI processor
- *
- * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _DAVINCI_PCM_H
-#define _DAVINCI_PCM_H
-
-#include <linux/genalloc.h>
-#include <linux/platform_data/davinci_asp.h>
-#include <linux/platform_data/edma.h>
-
-struct davinci_pcm_dma_params {
-       int channel;                    /* sync dma channel ID */
-       unsigned short acnt;
-       dma_addr_t dma_addr;            /* device physical address for DMA */
-       unsigned sram_size;
-       struct gen_pool *sram_pool;     /* SRAM gen_pool for ping pong */
-       enum dma_event_q asp_chan_q;    /* event queue number for ASP channel */
-       enum dma_event_q ram_chan_q;    /* event queue number for RAM channel */
-       unsigned char data_type;        /* xfer data type */
-       unsigned char convert_mono_stereo;
-       unsigned int fifo_level;
-};
-
-#if IS_ENABLED(CONFIG_SND_DAVINCI_SOC)
-int davinci_soc_platform_register(struct device *dev);
-#else
-static inline int davinci_soc_platform_register(struct device *dev)
-{
-       return 0;
-}
-#endif /* CONFIG_SND_DAVINCI_SOC */
-
-#endif
index 5bee04279ebede35dde51844be4c383862e914eb..fabd05f24aebe9b288735177fce0f5e3a250751c 100644 (file)
@@ -33,8 +33,9 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
-#include "davinci-pcm.h"
+#include "edma-pcm.h"
 #include "davinci-i2s.h"
 
 #define MOD_REG_BIT(val, mask, set) do { \
@@ -47,7 +48,8 @@
 
 struct davinci_vcif_dev {
        struct davinci_vc *davinci_vc;
-       struct davinci_pcm_dma_params   dma_params[2];
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       int dma_request[2];
 };
 
 static void davinci_vcif_start(struct snd_pcm_substream *substream)
@@ -93,8 +95,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
 {
        struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
-       struct davinci_pcm_dma_params *dma_params =
-                       &davinci_vcif_dev->dma_params[substream->stream];
        u32 w;
 
        /* Restart the codec before setup */
@@ -113,16 +113,12 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
        /* Determine xfer data type */
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U8:
-               dma_params->data_type = 0;
-
                MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
                            DAVINCI_VC_CTRL_RD_UNSIGNED |
                            DAVINCI_VC_CTRL_WD_BITS_8 |
                            DAVINCI_VC_CTRL_WD_UNSIGNED, 1);
                break;
        case SNDRV_PCM_FORMAT_S8:
-               dma_params->data_type = 1;
-
                MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
                            DAVINCI_VC_CTRL_WD_BITS_8, 1);
 
@@ -130,8 +126,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
                            DAVINCI_VC_CTRL_WD_UNSIGNED, 0);
                break;
        case SNDRV_PCM_FORMAT_S16_LE:
-               dma_params->data_type = 2;
-
                MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |
                            DAVINCI_VC_CTRL_RD_UNSIGNED |
                            DAVINCI_VC_CTRL_WD_BITS_8 |
@@ -142,8 +136,6 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       dma_params->acnt  = dma_params->data_type;
-
        writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
 
        return 0;
@@ -172,24 +164,25 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int davinci_vcif_startup(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
-       return 0;
-}
-
 #define DAVINCI_VCIF_RATES     SNDRV_PCM_RATE_8000_48000
 
 static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
-       .startup        = davinci_vcif_startup,
        .trigger        = davinci_vcif_trigger,
        .hw_params      = davinci_vcif_hw_params,
 };
 
+static int davinci_vcif_dai_probe(struct snd_soc_dai *dai)
+{
+       struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+       return 0;
+}
+
 static struct snd_soc_dai_driver davinci_vcif_dai = {
+       .probe = davinci_vcif_dai_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -225,16 +218,16 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
        /* DMA tx params */
        davinci_vcif_dev->davinci_vc = davinci_vc;
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel =
-                                       davinci_vc->davinci_vcif.dma_tx_channel;
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
-                                       davinci_vc->davinci_vcif.dma_tx_addr;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data =
+                               &davinci_vc->davinci_vcif.dma_tx_channel;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+                               davinci_vc->davinci_vcif.dma_tx_addr;
 
        /* DMA rx params */
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel =
-                                       davinci_vc->davinci_vcif.dma_rx_channel;
-       davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
-                                       davinci_vc->davinci_vcif.dma_rx_addr;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data =
+                               &davinci_vc->davinci_vcif.dma_rx_channel;
+       davinci_vcif_dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+                               davinci_vc->davinci_vcif.dma_rx_addr;
 
        dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
 
@@ -245,7 +238,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = davinci_soc_platform_register(&pdev->dev);
+       ret = edma_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
                snd_soc_unregister_component(&pdev->dev);
index 3f6959c8e2f71b44cf054445b85553960e8c94d9..de438871040bd43f8b1e6a05e4a479261e5ea4bd 100644 (file)
@@ -512,6 +512,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        memcpy(priv->dai_link, fsl_asoc_card_dai,
               sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
 
+       ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+               goto asrc_fail;
+       }
+
        /* Normal DAI Link */
        priv->dai_link[0].cpu_of_node = cpu_np;
        priv->dai_link[0].codec_of_node = codec_np;
index f8cf10e16ce9c7ef0d192668894354dae320b840..20e7400e2611e41ef057d9b2e22413a7c6a73c98 100644 (file)
@@ -53,9 +53,9 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
 
        /* Headphone jack detection */
        if (gpio_is_valid(data->jack_gpio)) {
-               ret = snd_soc_jack_new(rtd->codec, "Headphone",
-                                      SND_JACK_HEADPHONE | SND_JACK_BTN_0,
-                                      &headset_jack);
+               ret = snd_soc_card_jack_new(rtd->card, "Headphone",
+                                           SND_JACK_HEADPHONE | SND_JACK_BTN_0,
+                                           &headset_jack, NULL, 0);
                if (ret)
                        return ret;
 
index a958937ab405ce0d79e43942942c875ad69f66da..0653aa83c9273ca6afedfb0c9b8271df6cc79746 100644 (file)
@@ -205,16 +205,14 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        /* Headphone jack detection */
-       snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
-       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
-                             hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE,
+                             &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
        wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
 
        /* Microphone jack detection */
-       snd_soc_jack_new(codec, "Microphone",
-                        SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Microphone",
+                             SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack,
+                             mic_jack_pins, ARRAY_SIZE(mic_jack_pins));
        wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE,
                               SND_JACK_BTN_0);
 
index fb550b5869d21f73307d36d2edc88ebcffa61f0c..c49a408fc7a6a267e4a9d106d1019547b558c3ed 100644 (file)
@@ -176,11 +176,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
 
        if (gpio_is_valid(priv->gpio_hp_det)) {
-               snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE,
-                                &simple_card_hp_jack);
-               snd_soc_jack_add_pins(&simple_card_hp_jack,
-                                     ARRAY_SIZE(simple_card_hp_jack_pins),
-                                     simple_card_hp_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Headphones",
+                                     SND_JACK_HEADPHONE,
+                                     &simple_card_hp_jack,
+                                     simple_card_hp_jack_pins,
+                                     ARRAY_SIZE(simple_card_hp_jack_pins));
 
                simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
                simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert;
@@ -189,11 +189,11 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        if (gpio_is_valid(priv->gpio_mic_det)) {
-               snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE,
-                                &simple_card_mic_jack);
-               snd_soc_jack_add_pins(&simple_card_mic_jack,
-                                     ARRAY_SIZE(simple_card_mic_jack_pins),
-                                     simple_card_mic_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Mic Jack",
+                                     SND_JACK_MICROPHONE,
+                                     &simple_card_mic_jack,
+                                     simple_card_mic_jack_pins,
+                                     ARRAY_SIZE(simple_card_mic_jack_pins));
                simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
                simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert;
                snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
index 9cf7d01479adcbd82661c70344b5f5d4ad0969fe..fc5542034b9bf5a38afbbc1383e56c104a074781 100644 (file)
@@ -80,15 +80,9 @@ static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        int ret = 0;
-       ret = snd_soc_jack_new(codec, "Headset",
-               SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset);
-
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&broadwell_headset,
-               ARRAY_SIZE(broadwell_headset_pins),
-               broadwell_headset_pins);
+       ret = snd_soc_card_jack_new(rtd->card, "Headset",
+               SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
+               broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
        if (ret)
                return ret;
 
@@ -110,9 +104,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
        channels->min = channels->max = 2;
 
        /* set SSP0 to 16 bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S16_LE);
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
        return 0;
 }
 
index 9832afe7d22cb082e3d54dffce9f723f947716d7..d8b1f038da1c41ac9674b94efb072ca1e5c24f41 100644 (file)
@@ -84,7 +84,6 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = {
 static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
-       struct snd_soc_codec *codec = runtime->codec;
        struct snd_soc_card *card = runtime->card;
        struct byt_max98090_private *drv = snd_soc_card_get_drvdata(card);
        struct snd_soc_jack *jack = &drv->jack;
@@ -100,13 +99,9 @@ static int byt_max98090_init(struct snd_soc_pcm_runtime *runtime)
        }
 
        /* Enable jack detection */
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_LINEOUT | SND_JACK_HEADSET, jack);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(jack, ARRAY_SIZE(hs_jack_pins),
-                                   hs_jack_pins);
+       ret = snd_soc_card_jack_new(runtime->card, "Headset",
+                                   SND_JACK_LINEOUT | SND_JACK_HEADSET, jack,
+                                   hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
        if (ret)
                return ret;
 
index 59308629043e62dd2c2fa0bcc9e4cb126d7a74ba..3b262d01c1b370b9166d8e152486874d26f2aebd 100644 (file)
@@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        channels->min = channels->max = 2;
 
        /* set SSP2 to 24-bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S24_LE);
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
        return 0;
 }
 
index bd29617a9ab9d2a2c396b05e25a858855529bb45..012227997ed9ca07a64311597fb07aeeeaa4199a 100644 (file)
@@ -169,17 +169,17 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
                return ret;
        }
 
-       ret = snd_soc_jack_new(codec, "Headphone Jack",
-                               SND_JACK_HEADPHONE,
-                               &ctx->hp_jack);
+       ret = snd_soc_card_jack_new(runtime->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &ctx->hp_jack,
+                                   NULL, 0);
        if (ret) {
                dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
                return ret;
        }
 
-       ret = snd_soc_jack_new(codec, "Mic Jack",
-                               SND_JACK_MICROPHONE,
-                               &ctx->mic_jack);
+       ret = snd_soc_card_jack_new(runtime->card, "Mic Jack",
+                                   SND_JACK_MICROPHONE, &ctx->mic_jack,
+                                   NULL, 0);
        if (ret) {
                dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
                return ret;
@@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        channels->min = channels->max = 2;
 
        /* set SSP2 to 24-bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S24_LE);
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
        return 0;
 }
 
index ff016621583a63c85c96689270405cbc5640ab77..bc8dcacd5e6a08d2a4e0093c5f4349699e6d3a9d 100644 (file)
@@ -178,9 +178,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        channels->min = channels->max = 2;
 
        /* set SSP2 to 24-bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S24_LE);
+       params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
        return 0;
 }
 
@@ -217,7 +215,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
                .codec_dai_name = "snd-soc-dummy-dai",
                .codec_name = "snd-soc-dummy",
                .platform_name = "sst-mfld-platform",
-               .ignore_suspend = 1,
+               .nonatomic = true,
                .dynamic = 1,
                .dpcm_playback = 1,
                .dpcm_capture = 1,
@@ -240,13 +238,13 @@ static struct snd_soc_dai_link cht_dailink[] = {
                .cpu_dai_name = "ssp2-port",
                .platform_name = "sst-mfld-platform",
                .no_pcm = 1,
+               .nonatomic = true,
                .codec_dai_name = "rt5670-aif1",
                .codec_name = "i2c-10EC5670:00",
                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
                                        | SND_SOC_DAIFMT_CBS_CFS,
                .init = cht_codec_init,
                .be_hw_params_fixup = cht_codec_fixup,
-               .ignore_suspend = 1,
                .dpcm_playback = 1,
                .dpcm_capture = 1,
                .ops = &cht_be_ssp2_ops,
@@ -285,7 +283,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
                .name = "cht-bsw-rt5672",
-               .pm = &snd_soc_pm_ops,
        },
        .probe = snd_cht_mc_probe,
 };
index 35edf51a52aa92b3ace9156d4b3557f3db2282aa..00fddd3f5dfb8f7350180b8b564d282d4918331b 100644 (file)
@@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
        channels->min = channels->max = 2;
 
        /* set SSP0 to 16 bit */
-       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
-                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
-                                   SNDRV_PCM_FORMAT_S16_LE);
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
        return 0;
 }
 
index 90b7a57713a0234bb6aebfb9ae343c2a65c495ae..49c09a0add797ff95101bee1923b62254e3928a0 100644 (file)
@@ -228,10 +228,13 @@ static void mfld_jack_check(unsigned int intr_status)
 {
        struct mfld_jack_data jack_data;
 
+       if (!mfld_codec)
+               return;
+
        jack_data.mfld_jack = &mfld_jack;
        jack_data.intr_id = intr_status;
 
-       sn95031_jack_detection(&jack_data);
+       sn95031_jack_detection(mfld_codec, &jack_data);
        /* TODO: add american headset detection post gpiolib support */
 }
 
@@ -240,8 +243,6 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
        int ret_val;
 
-       mfld_codec = runtime->codec;
-
        /* default is earpiece pin, userspace sets it explcitly */
        snd_soc_dapm_disable_pin(dapm, "Headphones");
        /* default is lineout NC, userspace sets it explcitly */
@@ -254,20 +255,15 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        snd_soc_dapm_disable_pin(dapm, "LINEINR");
 
        /* Headset and button jack detection */
-       ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                       SND_JACK_BTN_1, &mfld_jack);
+       ret_val = snd_soc_card_jack_new(runtime->card,
+                       "Intel(R) MID Audio Jack", SND_JACK_HEADSET |
+                       SND_JACK_BTN_0 | SND_JACK_BTN_1, &mfld_jack,
+                       mfld_jack_pins, ARRAY_SIZE(mfld_jack_pins));
        if (ret_val) {
                pr_err("jack creation failed\n");
                return ret_val;
        }
 
-       ret_val = snd_soc_jack_add_pins(&mfld_jack,
-                       ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins);
-       if (ret_val) {
-               pr_err("adding jack pins failed\n");
-               return ret_val;
-       }
        ret_val = snd_soc_jack_add_zones(&mfld_jack,
                        ARRAY_SIZE(mfld_zones), mfld_zones);
        if (ret_val) {
@@ -275,6 +271,8 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
                return ret_val;
        }
 
+       mfld_codec = runtime->codec;
+
        /* we want to check if anything is inserted at boot,
         * so send a fake event to codec and it will read adc
         * to find if anything is there or not */
@@ -359,8 +357,6 @@ static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
 {
        struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
 
-       if (mfld_jack.codec == NULL)
-               return IRQ_HANDLED;
        mfld_jack_check(mc_drv_ctx->interrupt_status);
 
        return IRQ_HANDLED;
index 7523cbef87807f2b3ac0d4209e939a5b1bda7567..2fbaf2c75d1709e517a5fb1b1d8012f58865992c 100644 (file)
@@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
                ret_val = stream->ops->stream_drop(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                dev_dbg(rtd->dev, "sst: in pause\n");
                status = SST_PLATFORM_PAUSED;
                ret_val = stream->ops->stream_pause(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
                dev_dbg(rtd->dev, "sst: in pause release\n");
                status = SST_PLATFORM_RUNNING;
                ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
@@ -665,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 
 static int sst_soc_probe(struct snd_soc_platform *platform)
 {
+       struct sst_data *drv = dev_get_drvdata(platform->dev);
+
+       drv->soc_card = platform->component.card;
        return sst_dsp_init_v2_dpcm(platform);
 }
 
@@ -727,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+
+static int sst_soc_prepare(struct device *dev)
+{
+       struct sst_data *drv = dev_get_drvdata(dev);
+       int i;
+
+       /* suspend all pcms first */
+       snd_soc_suspend(drv->soc_card->dev);
+       snd_soc_poweroff(drv->soc_card->dev);
+
+       /* set the SSPs to idle */
+       for (i = 0; i < drv->soc_card->num_rtd; i++) {
+               struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+
+               if (dai->active) {
+                       send_ssp_cmd(dai, dai->name, 0);
+                       sst_handle_vb_timer(dai, false);
+               }
+       }
+
+       return 0;
+}
+
+static void sst_soc_complete(struct device *dev)
+{
+       struct sst_data *drv = dev_get_drvdata(dev);
+       int i;
+
+       /* restart SSPs */
+       for (i = 0; i < drv->soc_card->num_rtd; i++) {
+               struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+
+               if (dai->active) {
+                       sst_handle_vb_timer(dai, true);
+                       send_ssp_cmd(dai, dai->name, 1);
+               }
+       }
+       snd_soc_resume(drv->soc_card->dev);
+}
+
+#else
+
+#define sst_soc_prepare NULL
+#define sst_soc_complete NULL
+
+#endif
+
+
+static const struct dev_pm_ops sst_platform_pm = {
+       .prepare        = sst_soc_prepare,
+       .complete       = sst_soc_complete,
+};
+
 static struct platform_driver sst_platform_driver = {
        .driver         = {
                .name           = "sst-mfld-platform",
+               .pm             = &sst_platform_pm,
        },
        .probe          = sst_platform_probe,
        .remove         = sst_platform_remove,
index 79c8d1246a8fb396a4e703694f85e26fb378203b..9094314be2b043e724bfcf3db3f0f54b10dd61d4 100644 (file)
@@ -174,6 +174,7 @@ struct sst_data {
        struct sst_platform_data *pdata;
        struct snd_sst_bytes_v2 *byte_stream;
        struct mutex lock;
+       struct snd_soc_card *soc_card;
 };
 int sst_register_dsp(struct sst_device *sst);
 int sst_unregister_dsp(struct sst_device *sst);
index 11c578651c1c8cc778904ebb7665587cde44beef..1a7eeec444b14bc55ab8fcc434a23f39cdd91913 100644 (file)
@@ -423,23 +423,135 @@ static int intel_sst_runtime_suspend(struct device *dev)
        return ret;
 }
 
-static int intel_sst_runtime_resume(struct device *dev)
+static int intel_sst_suspend(struct device *dev)
 {
-       int ret = 0;
        struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+       struct sst_fw_save *fw_save;
+       int i, ret = 0;
 
-       if (ctx->sst_state == SST_RESET) {
-               ret = sst_load_fw(ctx);
-               if (ret) {
-                       dev_err(dev, "FW download fail %d\n", ret);
-                       sst_set_fw_state_locked(ctx, SST_RESET);
+       /* check first if we are already in SW reset */
+       if (ctx->sst_state == SST_RESET)
+               return 0;
+
+       /*
+        * check if any stream is active and running
+        * they should already by suspend by soc_suspend
+        */
+       for (i = 1; i <= ctx->info.max_streams; i++) {
+               struct stream_info *stream = &ctx->streams[i];
+
+               if (stream->status == STREAM_RUNNING) {
+                       dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
+                       return -EBUSY;
                }
        }
+       synchronize_irq(ctx->irq_num);
+       flush_workqueue(ctx->post_msg_wq);
+
+       /* Move the SST state to Reset */
+       sst_set_fw_state_locked(ctx, SST_RESET);
+
+       /* tell DSP we are suspending */
+       if (ctx->ops->save_dsp_context(ctx))
+               return -EBUSY;
+
+       /* save the memories */
+       fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
+       if (!fw_save)
+               return -ENOMEM;
+       fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
+       if (!fw_save->iram) {
+               ret = -ENOMEM;
+               goto iram;
+       }
+       fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
+       if (!fw_save->dram) {
+               ret = -ENOMEM;
+               goto dram;
+       }
+       fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
+       if (!fw_save->sram) {
+               ret = -ENOMEM;
+               goto sram;
+       }
+
+       fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
+       if (!fw_save->ddr) {
+               ret = -ENOMEM;
+               goto ddr;
+       }
+
+       memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
+       memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
+       memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
+       memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
+
+       ctx->fw_save = fw_save;
+       ctx->ops->reset(ctx);
+       return 0;
+ddr:
+       kfree(fw_save->sram);
+sram:
+       kfree(fw_save->dram);
+dram:
+       kfree(fw_save->iram);
+iram:
+       kfree(fw_save);
+       return ret;
+}
+
+static int intel_sst_resume(struct device *dev)
+{
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+       struct sst_fw_save *fw_save = ctx->fw_save;
+       int ret = 0;
+       struct sst_block *block;
+
+       if (!fw_save)
+               return 0;
+
+       sst_set_fw_state_locked(ctx, SST_FW_LOADING);
+
+       /* we have to restore the memory saved */
+       ctx->ops->reset(ctx);
+
+       ctx->fw_save = NULL;
+
+       memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base);
+       memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base);
+       memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
+       memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
+
+       kfree(fw_save->sram);
+       kfree(fw_save->dram);
+       kfree(fw_save->iram);
+       kfree(fw_save->ddr);
+       kfree(fw_save);
+
+       block = sst_create_block(ctx, 0, FW_DWNL_ID);
+       if (block == NULL)
+               return -ENOMEM;
+
+
+       /* start and wait for ack */
+       ctx->ops->start(ctx);
+       ret = sst_wait_timeout(ctx, block);
+       if (ret) {
+               dev_err(ctx->dev, "fw download failed %d\n", ret);
+               /* FW download failed due to timeout */
+               ret = -EBUSY;
+
+       } else {
+               sst_set_fw_state_locked(ctx, SST_FW_RUNNING);
+       }
+
+       sst_free_block(ctx, block);
        return ret;
 }
 
 const struct dev_pm_ops intel_sst_pm = {
+       .suspend = intel_sst_suspend,
+       .resume = intel_sst_resume,
        .runtime_suspend = intel_sst_runtime_suspend,
-       .runtime_resume = intel_sst_runtime_resume,
 };
 EXPORT_SYMBOL_GPL(intel_sst_pm);
index 562bc483d6b7f73924c6cd25fd2770b8c48bdc6b..3f493862e98dd0bd26b9e1733c4b05b729c963f5 100644 (file)
@@ -337,6 +337,13 @@ struct sst_shim_regs64 {
        u64 csr2;
 };
 
+struct sst_fw_save {
+       void *iram;
+       void *dram;
+       void *sram;
+       void *ddr;
+};
+
 /**
  * struct intel_sst_drv - driver ops
  *
@@ -428,6 +435,8 @@ struct intel_sst_drv {
         * persistent till worker thread gets called
         */
        char firmware_name[FW_NAME_SIZE];
+
+       struct sst_fw_save      *fw_save;
 };
 
 /* misc definitions */
@@ -544,4 +553,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx,
 int sst_context_init(struct intel_sst_drv *ctx);
 void sst_context_cleanup(struct intel_sst_drv *ctx);
 void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
+void memcpy32_toio(void __iomem *dst, const void *src, int count);
+void memcpy32_fromio(void *dst, const void __iomem *src, int count);
+
 #endif
index 5f75ef3cdd229613cd37a11ade1d3d3831385763..f0e4b99b3aeb13a61c1f5a5b5ad67de8c575d737 100644 (file)
@@ -138,12 +138,36 @@ int sst_get_stream(struct intel_sst_drv *ctx,
 static int sst_power_control(struct device *dev, bool state)
 {
        struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
-       dev_dbg(ctx->dev, "state:%d", state);
-       if (state == true)
-               return pm_runtime_get_sync(dev);
-       else
+       int ret = 0;
+       int usage_count = 0;
+
+#ifdef CONFIG_PM
+       usage_count = atomic_read(&dev->power.usage_count);
+#else
+       usage_count = 1;
+#endif
+
+       if (state == true) {
+               ret = pm_runtime_get_sync(dev);
+
+               dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
+               if (ret < 0) {
+                       dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
+                       return ret;
+               }
+               if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) {
+                       ret = sst_load_fw(ctx);
+                       if (ret) {
+                               dev_err(dev, "FW download fail %d\n", ret);
+                               sst_set_fw_state_locked(ctx, SST_RESET);
+                               ret = sst_pm_runtime_put(ctx);
+                       }
+               }
+       } else {
+               dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
                return sst_pm_runtime_put(ctx);
+       }
+       return ret;
 }
 
 /*
@@ -572,6 +596,35 @@ static int sst_stream_drop(struct device *dev, int str_id)
        return sst_drop_stream(ctx, str_id);
 }
 
+static int sst_stream_pause(struct device *dev, int str_id)
+{
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->sst_state != SST_FW_RUNNING)
+               return 0;
+
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+
+       return sst_pause_stream(ctx, str_id);
+}
+
+static int sst_stream_resume(struct device *dev, int str_id)
+{
+       struct stream_info *str_info;
+       struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+       if (ctx->sst_state != SST_FW_RUNNING)
+               return 0;
+
+       str_info = get_stream_info(ctx, str_id);
+       if (!str_info)
+               return -EINVAL;
+       return sst_resume_stream(ctx, str_id);
+}
+
 static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
 {
        int str_id = 0;
@@ -633,6 +686,8 @@ static struct sst_ops pcm_ops = {
        .stream_init = sst_stream_init,
        .stream_start = sst_stream_start,
        .stream_drop = sst_stream_drop,
+       .stream_pause = sst_stream_pause,
+       .stream_pause_release = sst_stream_resume,
        .stream_read_tstamp = sst_read_timestamp,
        .send_byte_stream = sst_send_byte_stream,
        .close = sst_close_pcm_stream,
index 7888cd707853db0a9819125d71cb063629514d9d..e88907ae8b154fb955037037e5c75aa62f67c8da 100644 (file)
 #include "sst.h"
 #include "../sst-dsp.h"
 
-static inline void memcpy32_toio(void __iomem *dst, const void *src, int count)
+void memcpy32_toio(void __iomem *dst, const void *src, int count)
+{
+       /* __iowrite32_copy uses 32-bit count values so divide by 4 for
+        * right count in words
+        */
+       __iowrite32_copy(dst, src, count/4);
+}
+
+void memcpy32_fromio(void *dst, const void __iomem *src, int count)
 {
        /* __iowrite32_copy uses 32-bit count values so divide by 4 for
         * right count in words
index a2cd3486ac554aceb9aeb75ed03314c4d30814fd..e7c78b0406b59c62fef534849571e49ed7b643d0 100644 (file)
@@ -100,17 +100,19 @@ config SND_OMAP_SOC_OMAP_TWL4030
 
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
        tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-       depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST)
+       depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || SOC_OMAP5 || COMPILE_TEST)
        select SND_OMAP_SOC_DMIC
        select SND_OMAP_SOC_MCPDM
        select SND_SOC_TWL6040
        select SND_SOC_DMIC
+       select COMMON_CLK_PALMAS if SOC_OMAP5
        help
          Say Y if you want to add support for SoC audio on OMAP boards using
          ABE and twl6040 codec. This driver currently supports:
          - SDP4430/Blaze boards
          - PandaBoard (4430)
          - PandaBoardES (4460)
+         - omap5-uevm (5432)
 
 config SND_OMAP_SOC_OMAP3_PANDORA
        tristate "SoC Audio support for OMAP3 Pandora"
index 706613077c155e93d7952aab02c49ccfccafaecc..16cc95fa45731b3f9ed6f47896b95b0eadf3a025 100644 (file)
@@ -479,8 +479,8 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 
        /* Add hook switch - can be used to control the codec from userspace
         * even if line discipline fails */
-       ret = snd_soc_jack_new(rtd->codec, "hook_switch",
-                               SND_JACK_HEADSET, &ams_delta_hook_switch);
+       ret = snd_soc_card_jack_new(card, "hook_switch", SND_JACK_HEADSET,
+                                   &ams_delta_hook_switch, NULL, 0);
        if (ret)
                dev_warn(card->dev,
                                "Failed to allocate resources for hook switch, "
index b9c65f1ad5a85ee9616704e0502bafc37e60a410..0843a68f277c2cffb0bdffa9a5a200b86544950f 100644 (file)
@@ -182,17 +182,17 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 
        /* Headset jack detection only if it is supported */
        if (priv->jack_detection) {
-               ret = snd_soc_jack_new(codec, "Headset Jack",
-                                       SND_JACK_HEADSET, &hs_jack);
+               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                           SND_JACK_HEADSET, &hs_jack,
+                                           hs_jack_pins,
+                                           ARRAY_SIZE(hs_jack_pins));
                if (ret)
                        return ret;
 
-               ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                                       hs_jack_pins);
                twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
        }
 
-       return ret;
+       return 0;
 }
 
 static const struct snd_soc_dapm_route dmic_audio_map[] = {
index 1343ecbf0bd5ee307d78d05f8a2e44abadc6c877..6bb623a2a4dfcfa3cda744ca8bef18575baec2d9 100644 (file)
@@ -39,7 +39,7 @@
 #define pcm_omap1510() 0
 #endif
 
-static const struct snd_pcm_hardware omap_pcm_hardware = {
+static struct snd_pcm_hardware omap_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
                                  SNDRV_PCM_INFO_INTERLEAVED |
@@ -53,6 +53,24 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
        .buffer_bytes_max       = 128 * 1024,
 };
 
+/* sDMA supports only 1, 2, and 4 byte transfer elements. */
+static void omap_pcm_limit_supported_formats(void)
+{
+       int i;
+
+       for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
+               switch (snd_pcm_format_physical_width(i)) {
+               case 8:
+               case 16:
+               case 32:
+                       omap_pcm_hardware.formats |= (1LL << i);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
 /* this may get called several times by oss emulation */
 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *params)
@@ -235,6 +253,7 @@ static struct snd_soc_platform_driver omap_soc_platform = {
 
 int omap_pcm_platform_register(struct device *dev)
 {
+       omap_pcm_limit_supported_formats();
        return devm_snd_soc_register_platform(dev, &omap_soc_platform);
 }
 EXPORT_SYMBOL_GPL(omap_pcm_platform_register);
index fb1f6bb87cd430d816e250a2b5d7317c4744c6a7..3673ada43bfb244fd7a17f90e7bc420e7e020ed1 100644 (file)
@@ -170,14 +170,10 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
        if (priv->jack_detect > 0) {
                hs_jack_gpios[0].gpio = priv->jack_detect;
 
-               ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
-                                      &priv->hs_jack);
-               if (ret)
-                       return ret;
-
-               ret = snd_soc_jack_add_pins(&priv->hs_jack,
-                                           ARRAY_SIZE(hs_jack_pins),
-                                           hs_jack_pins);
+               ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                           SND_JACK_HEADSET, &priv->hs_jack,
+                                           hs_jack_pins,
+                                           ARRAY_SIZE(hs_jack_pins));
                if (ret)
                        return ret;
 
index 7f299357c2d207c457cb9918a5b0a9cc618a3253..c2ddf0fbfa2895732a37d82d19b60c75408d67a7 100644 (file)
@@ -311,9 +311,9 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        /* AV jack detection */
-       err = snd_soc_jack_new(codec, "AV Jack",
-                              SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
-                              &rx51_av_jack);
+       err = snd_soc_card_jack_new(rtd->card, "AV Jack",
+                                   SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
+                                   &rx51_av_jack, NULL, 0);
        if (err) {
                dev_err(card->dev, "Failed to add AV Jack\n");
                return err;
index 73eb5ddf9753beb405b7d64fae88ede40d57bab2..9f8be7cd567e48c83218624ddfe2cad538ef28d7 100644 (file)
@@ -126,17 +126,12 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = {
  */
 static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Jack detection API stuff */
-       err = snd_soc_jack_new(codec, "Headphone Jack",
-                               SND_JACK_HEADPHONE, &hs_jack);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin),
-                                       hs_jack_pin);
+       err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &hs_jack, hs_jack_pin,
+                                   ARRAY_SIZE(hs_jack_pin));
        if (err)
                return err;
 
index 910336c5ebebd1486048552af7f598b6d7747b0d..c20bbc042425dacb2a478d247f9087b87ba8469c 100644 (file)
@@ -75,17 +75,12 @@ static struct snd_soc_card palm27x_asoc;
 
 static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Jack detection API stuff */
-       err = snd_soc_jack_new(codec, "Headphone Jack",
-                               SND_JACK_HEADPHONE, &hs_jack);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                               hs_jack_pins);
+       err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins,
+                                   ARRAY_SIZE(hs_jack_pins));
        if (err)
                return err;
 
index 5001dbb9b257764d9b88427de5bc86bebfba5a7b..1753c7d9e760e4bfa14e5b5ed8844b530e7413cf 100644 (file)
@@ -78,15 +78,12 @@ static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_codec *codec = rtd->codec;
 
        /* Headset jack detection */
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
-                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
-                       &hs_jack);
-       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                             hs_jack_pins);
-       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
-                        &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE |
+                             SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+                             &hs_jack, hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
+       snd_soc_card_jack_new(rtd->card, "Microphone Jack", SND_JACK_MICROPHONE,
+                             &mic_jack, mic_jack_pins,
+                             ARRAY_SIZE(mic_jack_pins));
 
        /* headphone, microphone detection & headset short detection */
        pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
index 76ccb172d0a77ed23be7b1fc441e388ce41b57fe..bcbfbe8303f7a03ac070c343e19e05d7847f8d8a 100644 (file)
@@ -143,13 +143,9 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_disable_pin(dapm, "MONO1");
 
        /* Jack detection API stuff */
-       ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
-                               &hs_jack);
-       if (ret)
-               goto err;
-
-       ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                               hs_jack_pins);
+       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
+                                   &hs_jack, hs_jack_pins,
+                                   ARRAY_SIZE(hs_jack_pins));
        if (ret)
                goto err;
 
index 59b044255b781c68c733f30f397ff266059ac507..c72e9fb26658ce17036761164e6fd9e083618841 100644 (file)
@@ -162,13 +162,8 @@ static struct platform_device *s3c24xx_snd_device;
 
 static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-               &hp_jack);
-
-       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
-               hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
+               &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
 
        snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
                hp_jack_gpios);
index 141519c21e21d7cbd425cb7b9a6d306278cabdf0..31a820eb0ac37b52992cbc986a17ce11d3c42ca1 100644 (file)
@@ -260,12 +260,12 @@ static int littlemill_late_probe(struct snd_soc_card *card)
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-                              SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                              SND_JACK_BTN_2 | SND_JACK_BTN_3 |
-                              SND_JACK_BTN_4 | SND_JACK_BTN_5,
-                              &littlemill_headset);
+       ret = snd_soc_card_jack_new(card, "Headset",
+                                   SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                   SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                                   SND_JACK_BTN_4 | SND_JACK_BTN_5,
+                                   &littlemill_headset, NULL, 0);
        if (ret)
                return ret;
 
index 243dea7ba38f81c7890ebea9af815cc80664111f..5f156093101e3ab2df8290841a656ab062ccd5af 100644 (file)
@@ -56,16 +56,10 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_LINEOUT | SND_JACK_HEADSET |
-                              SND_JACK_BTN_0,
-                              &lowland_headset);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&lowland_headset,
-                                   ARRAY_SIZE(lowland_headset_pins),
-                                   lowland_headset_pins);
+       ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                   &lowland_headset, lowland_headset_pins,
+                                   ARRAY_SIZE(lowland_headset_pins));
        if (ret)
                return ret;
 
index 873f2cb4bebe3e449d6d32821da672e0916626f0..35e37c457f1fd311ee982169010df6507939924d 100644 (file)
@@ -211,13 +211,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
 
 static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-               &hp_jack);
-
-       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
-               hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
+               &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
 
        snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
                hp_jack_gpios);
index 8291d2a5f1525957b6c4e021c8657d4590ce649e..dfbe2db1c4078da9de1d82d58d95573866cfe73e 100644 (file)
@@ -151,13 +151,10 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
 
        /* Headphone jack detection */
-       err = snd_soc_jack_new(codec, "Headphone Jack",
-                              SND_JACK_HEADPHONE, &smartq_jack);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
-                                   smartq_jack_pins);
+       err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                   SND_JACK_HEADPHONE, &smartq_jack,
+                                   smartq_jack_pins,
+                                   ARRAY_SIZE(smartq_jack_pins));
        if (err)
                return err;
 
index 5ec7c52282f201ba0b8bae03e26e936b6fb142b0..2dcb988bdff21272ffed15c7073e7f4643bee70f 100644 (file)
@@ -153,16 +153,10 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
                pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
        gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_LINEOUT | SND_JACK_HEADSET |
-                              SND_JACK_BTN_0,
-                              &speyside_headset);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&speyside_headset,
-                                   ARRAY_SIZE(speyside_headset_pins),
-                                   speyside_headset_pins);
+       ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                   &speyside_headset, speyside_headset_pins,
+                                   ARRAY_SIZE(speyside_headset_pins));
        if (ret)
                return ret;
 
index 9c80506527c4f3c87620fd48235f9e6f3e737834..85ccfb7188cb2d4b36101f14d0fa3dc024436f6f 100644 (file)
@@ -179,15 +179,10 @@ static int tobermory_late_probe(struct snd_soc_card *card)
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_HEADSET | SND_JACK_BTN_0,
-                              &tobermory_headset);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&tobermory_headset,
-                                   ARRAY_SIZE(tobermory_headset_pins),
-                                   tobermory_headset_pins);
+       ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET |
+                                   SND_JACK_BTN_0, &tobermory_headset,
+                                   tobermory_headset_pins,
+                                   ARRAY_SIZE(tobermory_headset_pins));
        if (ret)
                return ret;
 
index e5c990889dcc5e6d9a1ecca2682acf4384ab5ae5..07aa54385ae0242a2412f0bca9e570772e0877c1 100644 (file)
@@ -1578,6 +1578,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
                                          card->num_dapm_widgets);
 
+       if (card->of_dapm_widgets)
+               snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
+                                         card->num_of_dapm_widgets);
+
        /* initialise the sound card only once */
        if (card->probe) {
                ret = card->probe(card);
@@ -1633,6 +1637,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
                                        card->num_dapm_routes);
 
+       if (card->of_dapm_routes)
+               snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
+                                       card->num_of_dapm_routes);
+
        for (i = 0; i < card->num_links; i++) {
                if (card->dai_link[i].dai_fmt)
                        snd_soc_runtime_set_dai_fmt(&card->rtd[i],
@@ -3242,8 +3250,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
                widgets[i].name = wname;
        }
 
-       card->dapm_widgets = widgets;
-       card->num_dapm_widgets = num_widgets;
+       card->of_dapm_widgets = widgets;
+       card->num_of_dapm_widgets = num_widgets;
 
        return 0;
 }
@@ -3327,8 +3335,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                }
        }
 
-       card->num_dapm_routes = num_routes;
-       card->dapm_routes = routes;
+       card->num_of_dapm_routes = num_routes;
+       card->of_dapm_routes = routes;
 
        return 0;
 }
index 4380dcc064a5301a9fa4a077566d6bc450b1d28f..9f60c25c4568e7e1280e1ca28058c48c0ca65efa 100644 (file)
 #include <trace/events/asoc.h>
 
 /**
- * snd_soc_jack_new - Create a new jack
- * @codec: ASoC codec
+ * snd_soc_card_jack_new - Create a new jack
+ * @card:  ASoC card
  * @id:    an identifying string for this jack
  * @type:  a bitmask of enum snd_jack_type values that can be detected by
  *         this jack
  * @jack:  structure to use for the jack
+ * @pins:  Array of jack pins to be added to the jack or NULL
+ * @num_pins: Number of elements in the @pins array
  *
  * Creates a new jack object.
  *
  * Returns zero if successful, or a negative error code on failure.
  * On success jack will be initialised.
  */
-int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
-                    struct snd_soc_jack *jack)
+int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
+       struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
+       unsigned int num_pins)
 {
+       int ret;
+
        mutex_init(&jack->mutex);
-       jack->codec = codec;
+       jack->card = card;
        INIT_LIST_HEAD(&jack->pins);
        INIT_LIST_HEAD(&jack->jack_zones);
        BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
 
-       return snd_jack_new(codec->component.card->snd_card, id, type, &jack->jack);
+       ret = snd_jack_new(card->snd_card, id, type, &jack->jack);
+       if (ret)
+               return ret;
+
+       if (num_pins)
+               return snd_soc_jack_add_pins(jack, num_pins, pins);
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_jack_new);
+EXPORT_SYMBOL_GPL(snd_soc_card_jack_new);
 
 /**
  * snd_soc_jack_report - Report the current status for a jack
@@ -63,7 +75,6 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new);
  */
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
 {
-       struct snd_soc_codec *codec;
        struct snd_soc_dapm_context *dapm;
        struct snd_soc_jack_pin *pin;
        unsigned int sync = 0;
@@ -74,8 +85,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        if (!jack)
                return;
 
-       codec = jack->codec;
-       dapm =  &codec->dapm;
+       dapm = &jack->card->dapm;
 
        mutex_lock(&jack->mutex);
 
@@ -175,12 +185,12 @@ int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
 
        for (i = 0; i < count; i++) {
                if (!pins[i].pin) {
-                       dev_err(jack->codec->dev, "ASoC: No name for pin %d\n",
+                       dev_err(jack->card->dev, "ASoC: No name for pin %d\n",
                                i);
                        return -EINVAL;
                }
                if (!pins[i].mask) {
-                       dev_err(jack->codec->dev, "ASoC: No mask for pin %d"
+                       dev_err(jack->card->dev, "ASoC: No mask for pin %d"
                                " (%s)\n", i, pins[i].pin);
                        return -EINVAL;
                }
@@ -260,7 +270,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
 static irqreturn_t gpio_handler(int irq, void *data)
 {
        struct snd_soc_jack_gpio *gpio = data;
-       struct device *dev = gpio->jack->codec->component.card->dev;
+       struct device *dev = gpio->jack->card->dev;
 
        trace_snd_soc_jack_irq(gpio->name);
 
@@ -299,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 
        for (i = 0; i < count; i++) {
                if (!gpios[i].name) {
-                       dev_err(jack->codec->dev,
+                       dev_err(jack->card->dev,
                                "ASoC: No name for gpio at index %d\n", i);
                        ret = -EINVAL;
                        goto undo;
@@ -320,7 +330,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                } else {
                        /* legacy GPIO number */
                        if (!gpio_is_valid(gpios[i].gpio)) {
-                               dev_err(jack->codec->dev,
+                               dev_err(jack->card->dev,
                                        "ASoC: Invalid gpio %d\n",
                                        gpios[i].gpio);
                                ret = -EINVAL;
@@ -350,7 +360,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                if (gpios[i].wake) {
                        ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1);
                        if (ret != 0)
-                               dev_err(jack->codec->dev,
+                               dev_err(jack->card->dev,
                                        "ASoC: Failed to mark GPIO at index %d as wake source: %d\n",
                                        i, ret);
                }
index 6b0136e7cb88c2cebd96b12a6a85dc200f9838d3..6e3781e88f9adf52a35d79a45a785badd5d17709 100644 (file)
@@ -2511,6 +2511,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        /* DAPM dai link stream work */
        INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 
+       pcm->nonatomic = rtd->dai_link->nonatomic;
        rtd->pcm = pcm;
        pcm->private_data = rtd;
 
index 769aca2fc5f5af214fcd3505103e714e71531c7b..6dcd06a966c7c6149b8020f806e3bbb9c09af976 100644 (file)
@@ -106,11 +106,10 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-       snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
-                        &tegra_alc5632_hs_jack);
-       snd_soc_jack_add_pins(&tegra_alc5632_hs_jack,
-                       ARRAY_SIZE(tegra_alc5632_hs_jack_pins),
-                       tegra_alc5632_hs_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
+                             &tegra_alc5632_hs_jack,
+                             tegra_alc5632_hs_jack_pins,
+                             ARRAY_SIZE(tegra_alc5632_hs_jack_pins));
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det;
index af3fb997b75228927f4a32b53d65eb78938efd22..902da36581d1ba8af25494b8e69a2fec4415b1eb 100644 (file)
@@ -133,24 +133,26 @@ static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_SPK("Speakers", NULL),
        SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
 };
 
 static const struct snd_kcontrol_new tegra_max98090_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphones"),
        SOC_DAPM_PIN_SWITCH("Speakers"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
 };
 
 static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = codec_dai->codec;
        struct tegra_max98090 *machine = snd_soc_card_get_drvdata(rtd->card);
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
-               snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
-                               &tegra_max98090_hp_jack);
-               snd_soc_jack_add_pins(&tegra_max98090_hp_jack,
-                               ARRAY_SIZE(tegra_max98090_hp_jack_pins),
-                               tegra_max98090_hp_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Headphones",
+                                     SND_JACK_HEADPHONE,
+                                     &tegra_max98090_hp_jack,
+                                     tegra_max98090_hp_jack_pins,
+                                     ARRAY_SIZE(tegra_max98090_hp_jack_pins));
 
                tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det;
                snd_soc_jack_add_gpios(&tegra_max98090_hp_jack,
@@ -159,11 +161,11 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        if (gpio_is_valid(machine->gpio_mic_det)) {
-               snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-                                &tegra_max98090_mic_jack);
-               snd_soc_jack_add_pins(&tegra_max98090_mic_jack,
-                                     ARRAY_SIZE(tegra_max98090_mic_jack_pins),
-                                     tegra_max98090_mic_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Mic Jack",
+                                     SND_JACK_MICROPHONE,
+                                     &tegra_max98090_mic_jack,
+                                     tegra_max98090_mic_jack_pins,
+                                     ARRAY_SIZE(tegra_max98090_mic_jack_pins));
 
                tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det;
                snd_soc_jack_add_gpios(&tegra_max98090_mic_jack,
index ed759a3076b8b56063040c4c5f55bcdebff8bf05..773daecaa5e89f04700fafc049d922e37a1f35b7 100644 (file)
@@ -108,15 +108,11 @@ static const struct snd_kcontrol_new tegra_rt5640_controls[] = {
 
 static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_codec *codec = codec_dai->codec;
        struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-       snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
-                        &tegra_rt5640_hp_jack);
-       snd_soc_jack_add_pins(&tegra_rt5640_hp_jack,
-                       ARRAY_SIZE(tegra_rt5640_hp_jack_pins),
-                       tegra_rt5640_hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphones", SND_JACK_HEADPHONE,
+                             &tegra_rt5640_hp_jack, tegra_rt5640_hp_jack_pins,
+                             ARRAY_SIZE(tegra_rt5640_hp_jack_pins));
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det;
index e4cf978a6e3a9a194ef27a5abd62e2e2b67d2bf3..68d8b67e79c1528820fb5aa2801909e7e2aab289 100644 (file)
@@ -146,10 +146,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card);
 
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-                       &tegra_rt5677_hp_jack);
-       snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1,
-                       &tegra_rt5677_hp_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
+                             &tegra_rt5677_hp_jack,
+                             &tegra_rt5677_hp_jack_pins, 1);
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det;
@@ -158,10 +157,9 @@ static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
        }
 
 
-       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-                       &tegra_rt5677_mic_jack);
-       snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1,
-                       &tegra_rt5677_mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
+                             &tegra_rt5677_mic_jack,
+                             &tegra_rt5677_mic_jack_pins, 1);
 
        if (gpio_is_valid(machine->gpio_mic_present)) {
                tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present;
index e52420dae2b4b02df762df096ba366ad1c621d02..4a95b70f0cf082d6e65efdfca1e8608982037716 100644 (file)
@@ -177,21 +177,19 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
 
        if (gpio_is_valid(machine->gpio_hp_det)) {
                tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det;
-               snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-                               &tegra_wm8903_hp_jack);
-               snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
-                                       ARRAY_SIZE(tegra_wm8903_hp_jack_pins),
-                                       tegra_wm8903_hp_jack_pins);
+               snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+                                     SND_JACK_HEADPHONE, &tegra_wm8903_hp_jack,
+                                     tegra_wm8903_hp_jack_pins,
+                                     ARRAY_SIZE(tegra_wm8903_hp_jack_pins));
                snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
                                        1,
                                        &tegra_wm8903_hp_jack_gpio);
        }
 
-       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
-                        &tegra_wm8903_mic_jack);
-       snd_soc_jack_add_pins(&tegra_wm8903_mic_jack,
-                             ARRAY_SIZE(tegra_wm8903_mic_jack_pins),
-                             tegra_wm8903_mic_jack_pins);
+       snd_soc_card_jack_new(rtd->card, "Mic Jack", SND_JACK_MICROPHONE,
+                             &tegra_wm8903_mic_jack,
+                             tegra_wm8903_mic_jack_pins,
+                             ARRAY_SIZE(tegra_wm8903_mic_jack_pins));
        wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
                                0);
 
index 753a47de8459b7a0b505e72d2f660793d9ede885..353532b8aee444bc8269227242cb5854d1ae8a36 100644 (file)
@@ -1120,17 +1120,24 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
 /* Marantz/Denon USB DACs need a vendor cmd to switch
  * between PCM and native DSD mode
  */
+static bool is_marantz_denon_dac(unsigned int id)
+{
+       switch (id) {
+       case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
+       case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
+       case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+               return true;
+       }
+       return false;
+}
+
 int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
                              struct audioformat *fmt)
 {
        struct usb_device *dev = subs->dev;
        int err;
 
-       switch (subs->stream->chip->usb_id) {
-       case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
-       case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
-       case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
-
+       if (is_marantz_denon_dac(subs->stream->chip->usb_id)) {
                /* First switch to alt set 0, otherwise the mode switch cmd
                 * will not be accepted by the DAC
                 */
@@ -1203,17 +1210,10 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
        /* Marantz/Denon devices with USB DAC functionality need a delay
         * after each class compliant request
         */
-       if ((le16_to_cpu(dev->descriptor.idVendor) == 0x154e) &&
-           (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) {
-
-               switch (le16_to_cpu(dev->descriptor.idProduct)) {
-               case 0x1003: /* Denon DA300-USB */
-               case 0x3005: /* Marantz HD-DAC1 */
-               case 0x3006: /* Marantz SA-14S1 */
-                       mdelay(20);
-                       break;
-               }
-       }
+       if (is_marantz_denon_dac(USB_ID(le16_to_cpu(dev->descriptor.idVendor),
+                                       le16_to_cpu(dev->descriptor.idProduct)))
+           && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+               mdelay(20);
 
        /* Zoom R16/24 needs a tiny delay here, otherwise requests like
         * get/set frequency return as failed despite actually succeeding.
@@ -1268,15 +1268,9 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
        }
 
        /* Denon/Marantz devices with USB DAC functionality */
-       switch (chip->usb_id) {
-       case USB_ID(0x154e, 0x1003): /* Denon DA300-USB */
-       case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
-       case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+       if (is_marantz_denon_dac(chip->usb_id)) {
                if (fp->altsetting == 2)
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
-               break;
-       default:
-               break;
        }
 
        return 0;