Merge branch 'topic/hda-bus' into for-next
[linux-2.6-block.git] / sound / pci / hda / hda_controller.c
index a2ce773bdc624172b399afbb9207ed970b4c139f..a438e8540763711f479f894b27d6f239f28c637a 100644 (file)
@@ -30,7 +30,6 @@
 #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 +258,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 +405,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;
@@ -441,7 +447,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 +474,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 +714,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 +738,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)) {
 
-       *ts = ns_to_timespec(nsec);
+               snd_pcm_gettime(substream->runtime, system_ts);
+
+               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 +777,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 +797,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;
@@ -821,7 +843,7 @@ 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);
+       snd_hda_power_up(apcm->codec);
        err = hinfo->ops.open(hinfo, apcm->codec, substream);
        if (err < 0) {
                azx_release_device(azx_dev);
@@ -842,10 +864,12 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                return -EINVAL;
        }
 
-       /* 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;
@@ -877,7 +901,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 +911,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 +948,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 +956,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 +966,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;
 }
 
@@ -1164,7 +1186,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
        }
 
-       if (!bus->no_response_fallback)
+       if (bus->no_response_fallback)
                return -1;
 
        if (!chip->polling_mode && chip->poll_count < 2) {
@@ -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, 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)
 {