root/sound/pci/lola/lola_clock.c

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

DEFINITIONS

This source file includes following definitions.
  1. lola_sample_rate_convert
  2. check_gran_clock_compatibility
  3. lola_set_granularity
  4. lola_init_clock_widget
  5. lola_enable_clock_events
  6. lola_set_clock_index
  7. lola_update_ext_clock_freq
  8. lola_set_clock
  9. lola_set_sample_rate

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Support for Digigram Lola PCI-e boards
   4  *
   5  *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/init.h>
  10 #include <linux/delay.h>
  11 #include <sound/core.h>
  12 #include <sound/pcm.h>
  13 #include "lola.h"
  14 
  15 unsigned int lola_sample_rate_convert(unsigned int coded)
  16 {
  17         unsigned int freq;
  18 
  19         /* base frequency */
  20         switch (coded & 0x3) {
  21         case 0:     freq = 48000; break;
  22         case 1:     freq = 44100; break;
  23         case 2:     freq = 32000; break;
  24         default:    return 0;   /* error */
  25         }
  26 
  27         /* multiplier / devisor */
  28         switch (coded & 0x1c) {
  29         case (0 << 2):    break;
  30         case (4 << 2):    break;
  31         case (1 << 2):    freq *= 2; break;
  32         case (2 << 2):    freq *= 4; break;
  33         case (5 << 2):    freq /= 2; break;
  34         case (6 << 2):    freq /= 4; break;
  35         default:        return 0;   /* error */
  36         }
  37 
  38         /* ajustement */
  39         switch (coded & 0x60) {
  40         case (0 << 5):    break;
  41         case (1 << 5):    freq = (freq * 999) / 1000; break;
  42         case (2 << 5):    freq = (freq * 1001) / 1000; break;
  43         default:        return 0;   /* error */
  44         }
  45         return freq;
  46 }
  47 
  48 /*
  49  * Granualrity
  50  */
  51 
  52 #define LOLA_MAXFREQ_AT_GRANULARITY_MIN         48000
  53 #define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX   96000
  54 
  55 static bool check_gran_clock_compatibility(struct lola *chip,
  56                                            unsigned int val,
  57                                            unsigned int freq)
  58 {
  59         if (!chip->granularity)
  60                 return true;
  61 
  62         if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
  63             (val % LOLA_GRANULARITY_STEP) != 0)
  64                 return false;
  65 
  66         if (val == LOLA_GRANULARITY_MIN) {
  67                 if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
  68                         return false;
  69         } else if (val < LOLA_GRANULARITY_MAX) {
  70                 if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
  71                         return false;
  72         }
  73         return true;
  74 }
  75 
  76 int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
  77 {
  78         int err;
  79 
  80         if (!force) {
  81                 if (val == chip->granularity)
  82                         return 0;
  83 #if 0
  84                 /* change Gran only if there are no streams allocated ! */
  85                 if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
  86                         return -EBUSY;
  87 #endif
  88                 if (!check_gran_clock_compatibility(chip, val,
  89                                                     chip->clock.cur_freq))
  90                         return -EINVAL;
  91         }
  92 
  93         chip->granularity = val;
  94         val /= LOLA_GRANULARITY_STEP;
  95 
  96         /* audio function group */
  97         err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
  98                                val, 0);
  99         if (err < 0)
 100                 return err;
 101         /* this can be a very slow function !!! */
 102         usleep_range(400 * val, 20000);
 103         return lola_codec_flush(chip);
 104 }
 105 
 106 /*
 107  * Clock widget handling
 108  */
 109 
 110 int lola_init_clock_widget(struct lola *chip, int nid)
 111 {
 112         unsigned int val;
 113         int i, j, nitems, nb_verbs, idx, idx_list;
 114         int err;
 115 
 116         err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
 117         if (err < 0) {
 118                 dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
 119                 return err;
 120         }
 121 
 122         if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
 123                 dev_dbg(chip->card->dev, "No valid clock widget\n");
 124                 return 0;
 125         }
 126 
 127         chip->clock.nid = nid;
 128         chip->clock.items = val & 0xff;
 129         dev_dbg(chip->card->dev, "clock_list nid=%x, entries=%d\n", nid,
 130                     chip->clock.items);
 131         if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
 132                 dev_err(chip->card->dev, "CLOCK_LIST too big: %d\n",
 133                        chip->clock.items);
 134                 return -EINVAL;
 135         }
 136 
 137         nitems = chip->clock.items;
 138         nb_verbs = (nitems + 3) / 4;
 139         idx = 0;
 140         idx_list = 0;
 141         for (i = 0; i < nb_verbs; i++) {
 142                 unsigned int res_ex;
 143                 unsigned short items[4];
 144 
 145                 err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
 146                                       idx, 0, &val, &res_ex);
 147                 if (err < 0) {
 148                         dev_err(chip->card->dev, "Can't read CLOCK_LIST\n");
 149                         return -EINVAL;
 150                 }
 151 
 152                 items[0] = val & 0xfff;
 153                 items[1] = (val >> 16) & 0xfff;
 154                 items[2] = res_ex & 0xfff;
 155                 items[3] = (res_ex >> 16) & 0xfff;
 156 
 157                 for (j = 0; j < 4; j++) {
 158                         unsigned char type = items[j] >> 8;
 159                         unsigned int freq = items[j] & 0xff;
 160                         int format = LOLA_CLOCK_FORMAT_NONE;
 161                         bool add_clock = true;
 162                         if (type == LOLA_CLOCK_TYPE_INTERNAL) {
 163                                 freq = lola_sample_rate_convert(freq);
 164                                 if (freq < chip->sample_rate_min)
 165                                         add_clock = false;
 166                                 else if (freq == 48000) {
 167                                         chip->clock.cur_index = idx_list;
 168                                         chip->clock.cur_freq = 48000;
 169                                         chip->clock.cur_valid = true;
 170                                 }
 171                         } else if (type == LOLA_CLOCK_TYPE_VIDEO) {
 172                                 freq = lola_sample_rate_convert(freq);
 173                                 if (freq < chip->sample_rate_min)
 174                                         add_clock = false;
 175                                 /* video clock has a format (0:NTSC, 1:PAL)*/
 176                                 if (items[j] & 0x80)
 177                                         format = LOLA_CLOCK_FORMAT_NTSC;
 178                                 else
 179                                         format = LOLA_CLOCK_FORMAT_PAL;
 180                         }
 181                         if (add_clock) {
 182                                 struct lola_sample_clock *sc;
 183                                 sc = &chip->clock.sample_clock[idx_list];
 184                                 sc->type = type;
 185                                 sc->format = format;
 186                                 sc->freq = freq;
 187                                 /* keep the index used with the board */
 188                                 chip->clock.idx_lookup[idx_list] = idx;
 189                                 idx_list++;
 190                         } else {
 191                                 chip->clock.items--;
 192                         }
 193                         if (++idx >= nitems)
 194                                 break;
 195                 }
 196         }
 197         return 0;
 198 }
 199 
 200 /* enable unsolicited events of the clock widget */
 201 int lola_enable_clock_events(struct lola *chip)
 202 {
 203         unsigned int res;
 204         int err;
 205 
 206         err = lola_codec_read(chip, chip->clock.nid,
 207                               LOLA_VERB_SET_UNSOLICITED_ENABLE,
 208                               LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
 209                               0, &res, NULL);
 210         if (err < 0)
 211                 return err;
 212         if (res) {
 213                 dev_warn(chip->card->dev, "error in enable_clock_events %d\n",
 214                        res);
 215                 return -EINVAL;
 216         }
 217         return 0;
 218 }
 219 
 220 int lola_set_clock_index(struct lola *chip, unsigned int idx)
 221 {
 222         unsigned int res;
 223         int err;
 224 
 225         err = lola_codec_read(chip, chip->clock.nid,
 226                               LOLA_VERB_SET_CLOCK_SELECT,
 227                               chip->clock.idx_lookup[idx],
 228                               0, &res, NULL);
 229         if (err < 0)
 230                 return err;
 231         if (res) {
 232                 dev_warn(chip->card->dev, "error in set_clock %d\n", res);
 233                 return -EINVAL;
 234         }
 235         return 0;
 236 }
 237 
 238 bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
 239 {
 240         unsigned int tag;
 241 
 242         /* the current EXTERNAL clock information gets updated by interrupt
 243          * with an unsolicited response
 244          */
 245         if (!val)
 246                 return false;
 247         tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
 248         if (tag != LOLA_UNSOLICITED_TAG)
 249                 return false;
 250 
 251         /* only for current = external clocks */
 252         if (chip->clock.sample_clock[chip->clock.cur_index].type !=
 253             LOLA_CLOCK_TYPE_INTERNAL) {
 254                 chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
 255                 chip->clock.cur_valid = (val & 0x100) != 0;
 256         }
 257         return true;
 258 }
 259 
 260 int lola_set_clock(struct lola *chip, int idx)
 261 {
 262         int freq = 0;
 263         bool valid = false;
 264 
 265         if (idx == chip->clock.cur_index) {
 266                 /* current clock is allowed */
 267                 freq = chip->clock.cur_freq;
 268                 valid = chip->clock.cur_valid;
 269         } else if (chip->clock.sample_clock[idx].type ==
 270                    LOLA_CLOCK_TYPE_INTERNAL) {
 271                 /* internal clocks allowed */
 272                 freq = chip->clock.sample_clock[idx].freq;
 273                 valid = true;
 274         }
 275 
 276         if (!freq || !valid)
 277                 return -EINVAL;
 278 
 279         if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
 280                 return -EINVAL;
 281 
 282         if (idx != chip->clock.cur_index) {
 283                 int err = lola_set_clock_index(chip, idx);
 284                 if (err < 0)
 285                         return err;
 286                 /* update new settings */
 287                 chip->clock.cur_index = idx;
 288                 chip->clock.cur_freq = freq;
 289                 chip->clock.cur_valid = true;
 290         }
 291         return 0;
 292 }
 293 
 294 int lola_set_sample_rate(struct lola *chip, int rate)
 295 {
 296         int i;
 297 
 298         if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
 299                 return 0;
 300         /* search for new dwClockIndex */
 301         for (i = 0; i < chip->clock.items; i++) {
 302                 if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
 303                     chip->clock.sample_clock[i].freq == rate)
 304                         break;
 305         }
 306         if (i >= chip->clock.items)
 307                 return -EINVAL;
 308         return lola_set_clock(chip, i);
 309 }
 310 

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