root/drivers/media/pci/solo6x10/solo6x10-g723.c

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

DEFINITIONS

This source file includes following definitions.
  1. solo_g723_config
  2. solo_g723_isr
  3. snd_solo_hw_params
  4. snd_solo_hw_free
  5. snd_solo_pcm_open
  6. snd_solo_pcm_close
  7. snd_solo_pcm_trigger
  8. snd_solo_pcm_prepare
  9. snd_solo_pcm_pointer
  10. snd_solo_pcm_copy_user
  11. snd_solo_pcm_copy_kernel
  12. snd_solo_capture_volume_info
  13. snd_solo_capture_volume_get
  14. snd_solo_capture_volume_put
  15. solo_snd_pcm_init
  16. solo_g723_init
  17. solo_g723_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
   4  *
   5  * Original author:
   6  * Ben Collins <bcollins@ubuntu.com>
   7  *
   8  * Additional work by:
   9  * John Brooks <john.brooks@bluecherry.net>
  10  */
  11 
  12 #include <linux/kernel.h>
  13 #include <linux/mempool.h>
  14 #include <linux/poll.h>
  15 #include <linux/kthread.h>
  16 #include <linux/freezer.h>
  17 #include <linux/module.h>
  18 #include <linux/slab.h>
  19 
  20 #include <sound/core.h>
  21 #include <sound/initval.h>
  22 #include <sound/pcm.h>
  23 #include <sound/control.h>
  24 
  25 #include "solo6x10.h"
  26 #include "solo6x10-tw28.h"
  27 
  28 #define G723_FDMA_PAGES         32
  29 #define G723_PERIOD_BYTES       48
  30 #define G723_PERIOD_BLOCK       1024
  31 #define G723_FRAMES_PER_PAGE    48
  32 
  33 /* Sets up channels 16-19 for decoding and 0-15 for encoding */
  34 #define OUTMODE_MASK            0x300
  35 
  36 #define SAMPLERATE              8000
  37 #define BITRATE                 25
  38 
  39 /* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
  40  * is broken down to 20 * 48 byte regions (one for each channel possible)
  41  * with the rest of the page being dummy data. */
  42 #define PERIODS                 G723_FDMA_PAGES
  43 #define G723_INTR_ORDER         4 /* 0 - 4 */
  44 
  45 struct solo_snd_pcm {
  46         int                             on;
  47         spinlock_t                      lock;
  48         struct solo_dev                 *solo_dev;
  49         u8                              *g723_buf;
  50         dma_addr_t                      g723_dma;
  51 };
  52 
  53 static void solo_g723_config(struct solo_dev *solo_dev)
  54 {
  55         int clk_div;
  56 
  57         clk_div = (solo_dev->clock_mhz * 1000000)
  58                 / (SAMPLERATE * (BITRATE * 2) * 2);
  59 
  60         solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
  61                        SOLO_AUDIO_BITRATE(BITRATE)
  62                        | SOLO_AUDIO_CLK_DIV(clk_div));
  63 
  64         solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
  65                        SOLO_AUDIO_FDMA_INTERVAL(1)
  66                        | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER)
  67                        | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
  68 
  69         solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
  70                        SOLO_AUDIO_ENABLE
  71                        | SOLO_AUDIO_I2S_MODE
  72                        | SOLO_AUDIO_I2S_MULTI(3)
  73                        | SOLO_AUDIO_MODE(OUTMODE_MASK));
  74 }
  75 
  76 void solo_g723_isr(struct solo_dev *solo_dev)
  77 {
  78         struct snd_pcm_str *pstr =
  79                 &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
  80         struct snd_pcm_substream *ss;
  81         struct solo_snd_pcm *solo_pcm;
  82 
  83         for (ss = pstr->substream; ss != NULL; ss = ss->next) {
  84                 if (snd_pcm_substream_chip(ss) == NULL)
  85                         continue;
  86 
  87                 /* This means open() hasn't been called on this one */
  88                 if (snd_pcm_substream_chip(ss) == solo_dev)
  89                         continue;
  90 
  91                 /* Haven't triggered a start yet */
  92                 solo_pcm = snd_pcm_substream_chip(ss);
  93                 if (!solo_pcm->on)
  94                         continue;
  95 
  96                 snd_pcm_period_elapsed(ss);
  97         }
  98 }
  99 
 100 static int snd_solo_hw_params(struct snd_pcm_substream *ss,
 101                               struct snd_pcm_hw_params *hw_params)
 102 {
 103         return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
 104 }
 105 
 106 static int snd_solo_hw_free(struct snd_pcm_substream *ss)
 107 {
 108         return snd_pcm_lib_free_pages(ss);
 109 }
 110 
 111 static const struct snd_pcm_hardware snd_solo_pcm_hw = {
 112         .info                   = (SNDRV_PCM_INFO_MMAP |
 113                                    SNDRV_PCM_INFO_INTERLEAVED |
 114                                    SNDRV_PCM_INFO_BLOCK_TRANSFER |
 115                                    SNDRV_PCM_INFO_MMAP_VALID),
 116         .formats                = SNDRV_PCM_FMTBIT_U8,
 117         .rates                  = SNDRV_PCM_RATE_8000,
 118         .rate_min               = SAMPLERATE,
 119         .rate_max               = SAMPLERATE,
 120         .channels_min           = 1,
 121         .channels_max           = 1,
 122         .buffer_bytes_max       = G723_PERIOD_BYTES * PERIODS,
 123         .period_bytes_min       = G723_PERIOD_BYTES,
 124         .period_bytes_max       = G723_PERIOD_BYTES,
 125         .periods_min            = PERIODS,
 126         .periods_max            = PERIODS,
 127 };
 128 
 129 static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
 130 {
 131         struct solo_dev *solo_dev = snd_pcm_substream_chip(ss);
 132         struct solo_snd_pcm *solo_pcm;
 133 
 134         solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
 135         if (solo_pcm == NULL)
 136                 goto oom;
 137 
 138         solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev,
 139                                                   G723_PERIOD_BYTES,
 140                                                   &solo_pcm->g723_dma);
 141         if (solo_pcm->g723_buf == NULL)
 142                 goto oom;
 143 
 144         spin_lock_init(&solo_pcm->lock);
 145         solo_pcm->solo_dev = solo_dev;
 146         ss->runtime->hw = snd_solo_pcm_hw;
 147 
 148         snd_pcm_substream_chip(ss) = solo_pcm;
 149 
 150         return 0;
 151 
 152 oom:
 153         kfree(solo_pcm);
 154         return -ENOMEM;
 155 }
 156 
 157 static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
 158 {
 159         struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
 160 
 161         snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
 162         pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES,
 163                             solo_pcm->g723_buf, solo_pcm->g723_dma);
 164         kfree(solo_pcm);
 165 
 166         return 0;
 167 }
 168 
 169 static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
 170 {
 171         struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
 172         struct solo_dev *solo_dev = solo_pcm->solo_dev;
 173         int ret = 0;
 174 
 175         spin_lock(&solo_pcm->lock);
 176 
 177         switch (cmd) {
 178         case SNDRV_PCM_TRIGGER_START:
 179                 if (solo_pcm->on == 0) {
 180                         /* If this is the first user, switch on interrupts */
 181                         if (atomic_inc_return(&solo_dev->snd_users) == 1)
 182                                 solo_irq_on(solo_dev, SOLO_IRQ_G723);
 183                         solo_pcm->on = 1;
 184                 }
 185                 break;
 186         case SNDRV_PCM_TRIGGER_STOP:
 187                 if (solo_pcm->on) {
 188                         /* If this was our last user, switch them off */
 189                         if (atomic_dec_return(&solo_dev->snd_users) == 0)
 190                                 solo_irq_off(solo_dev, SOLO_IRQ_G723);
 191                         solo_pcm->on = 0;
 192                 }
 193                 break;
 194         default:
 195                 ret = -EINVAL;
 196         }
 197 
 198         spin_unlock(&solo_pcm->lock);
 199 
 200         return ret;
 201 }
 202 
 203 static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
 204 {
 205         return 0;
 206 }
 207 
 208 static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
 209 {
 210         struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
 211         struct solo_dev *solo_dev = solo_pcm->solo_dev;
 212         snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
 213 
 214         return idx * G723_FRAMES_PER_PAGE;
 215 }
 216 
 217 static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel,
 218                                   unsigned long pos, void __user *dst,
 219                                   unsigned long count)
 220 {
 221         struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
 222         struct solo_dev *solo_dev = solo_pcm->solo_dev;
 223         int err, i;
 224 
 225         for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
 226                 int page = (pos / G723_FRAMES_PER_PAGE) + i;
 227 
 228                 err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma,
 229                                      SOLO_G723_EXT_ADDR(solo_dev) +
 230                                      (page * G723_PERIOD_BLOCK) +
 231                                      (ss->number * G723_PERIOD_BYTES),
 232                                      G723_PERIOD_BYTES, 0, 0);
 233                 if (err)
 234                         return err;
 235 
 236                 if (copy_to_user(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES))
 237                         return -EFAULT;
 238                 dst += G723_PERIOD_BYTES;
 239         }
 240 
 241         return 0;
 242 }
 243 
 244 static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel,
 245                                     unsigned long pos, void *dst,
 246                                     unsigned long count)
 247 {
 248         struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
 249         struct solo_dev *solo_dev = solo_pcm->solo_dev;
 250         int err, i;
 251 
 252         for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
 253                 int page = (pos / G723_FRAMES_PER_PAGE) + i;
 254 
 255                 err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma,
 256                                      SOLO_G723_EXT_ADDR(solo_dev) +
 257                                      (page * G723_PERIOD_BLOCK) +
 258                                      (ss->number * G723_PERIOD_BYTES),
 259                                      G723_PERIOD_BYTES, 0, 0);
 260                 if (err)
 261                         return err;
 262 
 263                 memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES);
 264                 dst += G723_PERIOD_BYTES;
 265         }
 266 
 267         return 0;
 268 }
 269 
 270 static const struct snd_pcm_ops snd_solo_pcm_ops = {
 271         .open = snd_solo_pcm_open,
 272         .close = snd_solo_pcm_close,
 273         .ioctl = snd_pcm_lib_ioctl,
 274         .hw_params = snd_solo_hw_params,
 275         .hw_free = snd_solo_hw_free,
 276         .prepare = snd_solo_pcm_prepare,
 277         .trigger = snd_solo_pcm_trigger,
 278         .pointer = snd_solo_pcm_pointer,
 279         .copy_user = snd_solo_pcm_copy_user,
 280         .copy_kernel = snd_solo_pcm_copy_kernel,
 281 };
 282 
 283 static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
 284                                         struct snd_ctl_elem_info *info)
 285 {
 286         info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 287         info->count = 1;
 288         info->value.integer.min = 0;
 289         info->value.integer.max = 15;
 290         info->value.integer.step = 1;
 291 
 292         return 0;
 293 }
 294 
 295 static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
 296                                        struct snd_ctl_elem_value *value)
 297 {
 298         struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
 299         u8 ch = value->id.numid - 1;
 300 
 301         value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
 302 
 303         return 0;
 304 }
 305 
 306 static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
 307                                        struct snd_ctl_elem_value *value)
 308 {
 309         struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
 310         u8 ch = value->id.numid - 1;
 311         u8 old_val;
 312 
 313         old_val = tw28_get_audio_gain(solo_dev, ch);
 314         if (old_val == value->value.integer.value[0])
 315                 return 0;
 316 
 317         tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
 318 
 319         return 1;
 320 }
 321 
 322 static const struct snd_kcontrol_new snd_solo_capture_volume = {
 323         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 324         .name = "Capture Volume",
 325         .info = snd_solo_capture_volume_info,
 326         .get = snd_solo_capture_volume_get,
 327         .put = snd_solo_capture_volume_put,
 328 };
 329 
 330 static int solo_snd_pcm_init(struct solo_dev *solo_dev)
 331 {
 332         struct snd_card *card = solo_dev->snd_card;
 333         struct snd_pcm *pcm;
 334         struct snd_pcm_substream *ss;
 335         int ret;
 336         int i;
 337 
 338         ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
 339                           &pcm);
 340         if (ret < 0)
 341                 return ret;
 342 
 343         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
 344                         &snd_solo_pcm_ops);
 345 
 346         snd_pcm_chip(pcm) = solo_dev;
 347         pcm->info_flags = 0;
 348         strscpy(pcm->name, card->shortname, sizeof(pcm->name));
 349 
 350         for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
 351              ss; ss = ss->next, i++)
 352                 sprintf(ss->name, "Camera #%d Audio", i);
 353 
 354         snd_pcm_lib_preallocate_pages_for_all(pcm,
 355                                         SNDRV_DMA_TYPE_CONTINUOUS,
 356                                         snd_dma_continuous_data(GFP_KERNEL),
 357                                         G723_PERIOD_BYTES * PERIODS,
 358                                         G723_PERIOD_BYTES * PERIODS);
 359 
 360         solo_dev->snd_pcm = pcm;
 361 
 362         return 0;
 363 }
 364 
 365 int solo_g723_init(struct solo_dev *solo_dev)
 366 {
 367         static struct snd_device_ops ops = { };
 368         struct snd_card *card;
 369         struct snd_kcontrol_new kctl;
 370         char name[32];
 371         int ret;
 372 
 373         atomic_set(&solo_dev->snd_users, 0);
 374 
 375         /* Allows for easier mapping between video and audio */
 376         sprintf(name, "Softlogic%d", solo_dev->vfd->num);
 377 
 378         ret = snd_card_new(&solo_dev->pdev->dev,
 379                            SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
 380                            &solo_dev->snd_card);
 381         if (ret < 0)
 382                 return ret;
 383 
 384         card = solo_dev->snd_card;
 385 
 386         strscpy(card->driver, SOLO6X10_NAME, sizeof(card->driver));
 387         strscpy(card->shortname, "SOLO-6x10 Audio", sizeof(card->shortname));
 388         sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
 389                 pci_name(solo_dev->pdev), solo_dev->pdev->irq);
 390 
 391         ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
 392         if (ret < 0)
 393                 goto snd_error;
 394 
 395         /* Mixer controls */
 396         strscpy(card->mixername, "SOLO-6x10", sizeof(card->mixername));
 397         kctl = snd_solo_capture_volume;
 398         kctl.count = solo_dev->nr_chans;
 399 
 400         ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
 401         if (ret < 0)
 402                 return ret;
 403 
 404         ret = solo_snd_pcm_init(solo_dev);
 405         if (ret < 0)
 406                 goto snd_error;
 407 
 408         ret = snd_card_register(card);
 409         if (ret < 0)
 410                 goto snd_error;
 411 
 412         solo_g723_config(solo_dev);
 413 
 414         dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
 415 
 416         return 0;
 417 
 418 snd_error:
 419         snd_card_free(card);
 420         return ret;
 421 }
 422 
 423 void solo_g723_exit(struct solo_dev *solo_dev)
 424 {
 425         if (!solo_dev->snd_card)
 426                 return;
 427 
 428         solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
 429         solo_irq_off(solo_dev, SOLO_IRQ_G723);
 430 
 431         snd_card_free(solo_dev->snd_card);
 432         solo_dev->snd_card = NULL;
 433 }

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