root/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_bcm2835_playback_free
  2. bcm2835_playback_fifo
  3. snd_bcm2835_playback_open_generic
  4. snd_bcm2835_playback_open
  5. snd_bcm2835_playback_spdif_open
  6. snd_bcm2835_playback_close
  7. snd_bcm2835_pcm_hw_params
  8. snd_bcm2835_pcm_hw_free
  9. snd_bcm2835_pcm_prepare
  10. snd_bcm2835_pcm_transfer
  11. snd_bcm2835_pcm_ack
  12. snd_bcm2835_pcm_trigger
  13. snd_bcm2835_pcm_pointer
  14. snd_bcm2835_new_pcm

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
   3 
   4 #include <linux/interrupt.h>
   5 #include <linux/slab.h>
   6 
   7 #include <sound/asoundef.h>
   8 
   9 #include "bcm2835.h"
  10 
  11 /* hardware definition */
  12 static const struct snd_pcm_hardware snd_bcm2835_playback_hw = {
  13         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
  14                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
  15                  SNDRV_PCM_INFO_SYNC_APPLPTR),
  16         .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
  17         .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
  18         .rate_min = 8000,
  19         .rate_max = 48000,
  20         .channels_min = 1,
  21         .channels_max = 2,
  22         .buffer_bytes_max = 128 * 1024,
  23         .period_bytes_min = 1 * 1024,
  24         .period_bytes_max = 128 * 1024,
  25         .periods_min = 1,
  26         .periods_max = 128,
  27 };
  28 
  29 static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
  30         .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
  31                  SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
  32                  SNDRV_PCM_INFO_SYNC_APPLPTR),
  33         .formats = SNDRV_PCM_FMTBIT_S16_LE,
  34         .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
  35         SNDRV_PCM_RATE_48000,
  36         .rate_min = 44100,
  37         .rate_max = 48000,
  38         .channels_min = 2,
  39         .channels_max = 2,
  40         .buffer_bytes_max = 128 * 1024,
  41         .period_bytes_min = 1 * 1024,
  42         .period_bytes_max = 128 * 1024,
  43         .periods_min = 1,
  44         .periods_max = 128,
  45 };
  46 
  47 static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
  48 {
  49         kfree(runtime->private_data);
  50 }
  51 
  52 void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream,
  53                            unsigned int bytes)
  54 {
  55         struct snd_pcm_substream *substream = alsa_stream->substream;
  56         unsigned int pos;
  57 
  58         if (!alsa_stream->period_size)
  59                 return;
  60 
  61         if (bytes >= alsa_stream->buffer_size) {
  62                 snd_pcm_stream_lock(substream);
  63                 snd_pcm_stop(substream,
  64                              alsa_stream->draining ?
  65                              SNDRV_PCM_STATE_SETUP :
  66                              SNDRV_PCM_STATE_XRUN);
  67                 snd_pcm_stream_unlock(substream);
  68                 return;
  69         }
  70 
  71         pos = atomic_read(&alsa_stream->pos);
  72         pos += bytes;
  73         pos %= alsa_stream->buffer_size;
  74         atomic_set(&alsa_stream->pos, pos);
  75 
  76         alsa_stream->period_offset += bytes;
  77         alsa_stream->interpolate_start = ktime_get();
  78         if (alsa_stream->period_offset >= alsa_stream->period_size) {
  79                 alsa_stream->period_offset %= alsa_stream->period_size;
  80                 snd_pcm_period_elapsed(substream);
  81         }
  82 }
  83 
  84 /* open callback */
  85 static int snd_bcm2835_playback_open_generic(
  86         struct snd_pcm_substream *substream, int spdif)
  87 {
  88         struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
  89         struct snd_pcm_runtime *runtime = substream->runtime;
  90         struct bcm2835_alsa_stream *alsa_stream;
  91         int idx;
  92         int err;
  93 
  94         mutex_lock(&chip->audio_mutex);
  95         idx = substream->number;
  96 
  97         if (spdif && chip->opened) {
  98                 err = -EBUSY;
  99                 goto out;
 100         } else if (!spdif && (chip->opened & (1 << idx))) {
 101                 err = -EBUSY;
 102                 goto out;
 103         }
 104         if (idx >= MAX_SUBSTREAMS) {
 105                 dev_err(chip->dev,
 106                         "substream(%d) device doesn't exist max(%d) substreams allowed\n",
 107                         idx, MAX_SUBSTREAMS);
 108                 err = -ENODEV;
 109                 goto out;
 110         }
 111 
 112         alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
 113         if (!alsa_stream) {
 114                 err = -ENOMEM;
 115                 goto out;
 116         }
 117 
 118         /* Initialise alsa_stream */
 119         alsa_stream->chip = chip;
 120         alsa_stream->substream = substream;
 121         alsa_stream->idx = idx;
 122 
 123         err = bcm2835_audio_open(alsa_stream);
 124         if (err) {
 125                 kfree(alsa_stream);
 126                 goto out;
 127         }
 128         runtime->private_data = alsa_stream;
 129         runtime->private_free = snd_bcm2835_playback_free;
 130         if (spdif) {
 131                 runtime->hw = snd_bcm2835_playback_spdif_hw;
 132         } else {
 133                 /* clear spdif status, as we are not in spdif mode */
 134                 chip->spdif_status = 0;
 135                 runtime->hw = snd_bcm2835_playback_hw;
 136         }
 137         /* minimum 16 bytes alignment (for vchiq bulk transfers) */
 138         snd_pcm_hw_constraint_step(runtime,
 139                                    0,
 140                                    SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 141                                    16);
 142 
 143         /* position update is in 10ms order */
 144         snd_pcm_hw_constraint_minmax(runtime,
 145                                      SNDRV_PCM_HW_PARAM_PERIOD_TIME,
 146                                      10 * 1000, UINT_MAX);
 147 
 148         chip->alsa_stream[idx] = alsa_stream;
 149 
 150         chip->opened |= (1 << idx);
 151 
 152 out:
 153         mutex_unlock(&chip->audio_mutex);
 154 
 155         return err;
 156 }
 157 
 158 static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
 159 {
 160         return snd_bcm2835_playback_open_generic(substream, 0);
 161 }
 162 
 163 static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
 164 {
 165         return snd_bcm2835_playback_open_generic(substream, 1);
 166 }
 167 
 168 static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
 169 {
 170         struct bcm2835_alsa_stream *alsa_stream;
 171         struct snd_pcm_runtime *runtime;
 172         struct bcm2835_chip *chip;
 173 
 174         chip = snd_pcm_substream_chip(substream);
 175         mutex_lock(&chip->audio_mutex);
 176         runtime = substream->runtime;
 177         alsa_stream = runtime->private_data;
 178 
 179         alsa_stream->period_size = 0;
 180         alsa_stream->buffer_size = 0;
 181 
 182         bcm2835_audio_close(alsa_stream);
 183         alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
 184         /*
 185          * Do not free up alsa_stream here, it will be freed up by
 186          * runtime->private_free callback we registered in *_open above
 187          */
 188 
 189         chip->opened &= ~(1 << substream->number);
 190 
 191         mutex_unlock(&chip->audio_mutex);
 192 
 193         return 0;
 194 }
 195 
 196 static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
 197         struct snd_pcm_hw_params *params)
 198 {
 199         return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
 200 }
 201 
 202 static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
 203 {
 204         return snd_pcm_lib_free_pages(substream);
 205 }
 206 
 207 static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
 208 {
 209         struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
 210         struct snd_pcm_runtime *runtime = substream->runtime;
 211         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
 212         int channels;
 213         int err;
 214 
 215         /* notify the vchiq that it should enter spdif passthrough mode by
 216          * setting channels=0 (see
 217          * https://github.com/raspberrypi/linux/issues/528)
 218          */
 219         if (chip->spdif_status & IEC958_AES0_NONAUDIO)
 220                 channels = 0;
 221         else
 222                 channels = runtime->channels;
 223 
 224         err = bcm2835_audio_set_params(alsa_stream, channels,
 225                                        runtime->rate,
 226                                        snd_pcm_format_width(runtime->format));
 227         if (err < 0)
 228                 return err;
 229 
 230         memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
 231 
 232         alsa_stream->pcm_indirect.hw_buffer_size =
 233                 alsa_stream->pcm_indirect.sw_buffer_size =
 234                 snd_pcm_lib_buffer_bytes(substream);
 235 
 236         alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
 237         alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
 238         atomic_set(&alsa_stream->pos, 0);
 239         alsa_stream->period_offset = 0;
 240         alsa_stream->draining = false;
 241         alsa_stream->interpolate_start = ktime_get();
 242 
 243         return 0;
 244 }
 245 
 246 static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
 247         struct snd_pcm_indirect *rec, size_t bytes)
 248 {
 249         struct snd_pcm_runtime *runtime = substream->runtime;
 250         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
 251         void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
 252 
 253         bcm2835_audio_write(alsa_stream, bytes, src);
 254 }
 255 
 256 static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
 257 {
 258         struct snd_pcm_runtime *runtime = substream->runtime;
 259         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
 260         struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
 261 
 262         return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
 263                                                   snd_bcm2835_pcm_transfer);
 264 }
 265 
 266 /* trigger callback */
 267 static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 268 {
 269         struct snd_pcm_runtime *runtime = substream->runtime;
 270         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
 271 
 272         switch (cmd) {
 273         case SNDRV_PCM_TRIGGER_START:
 274                 return bcm2835_audio_start(alsa_stream);
 275         case SNDRV_PCM_TRIGGER_DRAIN:
 276                 alsa_stream->draining = true;
 277                 return bcm2835_audio_drain(alsa_stream);
 278         case SNDRV_PCM_TRIGGER_STOP:
 279                 return bcm2835_audio_stop(alsa_stream);
 280         default:
 281                 return -EINVAL;
 282         }
 283 }
 284 
 285 /* pointer callback */
 286 static snd_pcm_uframes_t
 287 snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
 288 {
 289         struct snd_pcm_runtime *runtime = substream->runtime;
 290         struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
 291         ktime_t now = ktime_get();
 292 
 293         /* Give userspace better delay reporting by interpolating between GPU
 294          * notifications, assuming audio speed is close enough to the clock
 295          * used for ktime
 296          */
 297 
 298         if ((ktime_to_ns(alsa_stream->interpolate_start)) &&
 299             (ktime_compare(alsa_stream->interpolate_start, now) < 0)) {
 300                 u64 interval =
 301                         (ktime_to_ns(ktime_sub(now,
 302                                 alsa_stream->interpolate_start)));
 303                 u64 frames_output_in_interval =
 304                         div_u64((interval * runtime->rate), 1000000000);
 305                 snd_pcm_sframes_t frames_output_in_interval_sized =
 306                         -frames_output_in_interval;
 307                 runtime->delay = frames_output_in_interval_sized;
 308         }
 309 
 310         return snd_pcm_indirect_playback_pointer(substream,
 311                 &alsa_stream->pcm_indirect,
 312                 atomic_read(&alsa_stream->pos));
 313 }
 314 
 315 /* operators */
 316 static const struct snd_pcm_ops snd_bcm2835_playback_ops = {
 317         .open = snd_bcm2835_playback_open,
 318         .close = snd_bcm2835_playback_close,
 319         .ioctl = snd_pcm_lib_ioctl,
 320         .hw_params = snd_bcm2835_pcm_hw_params,
 321         .hw_free = snd_bcm2835_pcm_hw_free,
 322         .prepare = snd_bcm2835_pcm_prepare,
 323         .trigger = snd_bcm2835_pcm_trigger,
 324         .pointer = snd_bcm2835_pcm_pointer,
 325         .ack = snd_bcm2835_pcm_ack,
 326 };
 327 
 328 static const struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
 329         .open = snd_bcm2835_playback_spdif_open,
 330         .close = snd_bcm2835_playback_close,
 331         .ioctl = snd_pcm_lib_ioctl,
 332         .hw_params = snd_bcm2835_pcm_hw_params,
 333         .hw_free = snd_bcm2835_pcm_hw_free,
 334         .prepare = snd_bcm2835_pcm_prepare,
 335         .trigger = snd_bcm2835_pcm_trigger,
 336         .pointer = snd_bcm2835_pcm_pointer,
 337         .ack = snd_bcm2835_pcm_ack,
 338 };
 339 
 340 /* create a pcm device */
 341 int snd_bcm2835_new_pcm(struct bcm2835_chip *chip, const char *name,
 342                         int idx, enum snd_bcm2835_route route,
 343                         u32 numchannels, bool spdif)
 344 {
 345         struct snd_pcm *pcm;
 346         int err;
 347 
 348         err = snd_pcm_new(chip->card, name, idx, numchannels, 0, &pcm);
 349         if (err)
 350                 return err;
 351 
 352         pcm->private_data = chip;
 353         pcm->nonatomic = true;
 354         strcpy(pcm->name, name);
 355         if (!spdif) {
 356                 chip->dest = route;
 357                 chip->volume = 0;
 358                 chip->mute = CTRL_VOL_UNMUTE;
 359         }
 360 
 361         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 362                         spdif ? &snd_bcm2835_playback_spdif_ops :
 363                         &snd_bcm2835_playback_ops);
 364 
 365         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 366                 chip->card->dev, 128 * 1024, 128 * 1024);
 367 
 368         if (spdif)
 369                 chip->pcm_spdif = pcm;
 370         else
 371                 chip->pcm = pcm;
 372         return 0;
 373 }

/* [<][>][^][v][top][bottom][index][help] */