linux/sound/firewire/bebob/bebob_focusrite.c
<<
>>
Prefs
   1/*
   2 * bebob_focusrite.c - a part of driver for BeBoB based devices
   3 *
   4 * Copyright (c) 2013-2014 Takashi Sakamoto
   5 *
   6 * Licensed under the terms of the GNU General Public License, version 2.
   7 */
   8
   9#include "./bebob.h"
  10
  11#define ANA_IN  "Analog In"
  12#define DIG_IN  "Digital In"
  13#define ANA_OUT "Analog Out"
  14#define DIG_OUT "Digital Out"
  15#define STM_IN  "Stream In"
  16
  17#define SAFFIRE_ADDRESS_BASE                    0x000100000000ULL
  18
  19#define SAFFIRE_OFFSET_CLOCK_SOURCE             0x00f8
  20#define SAFFIREPRO_OFFSET_CLOCK_SOURCE          0x0174
  21
  22/* whether sync to external device or not */
  23#define SAFFIRE_OFFSET_CLOCK_SYNC_EXT           0x013c
  24#define SAFFIRE_LE_OFFSET_CLOCK_SYNC_EXT        0x0432
  25#define SAFFIREPRO_OFFSET_CLOCK_SYNC_EXT        0x0164
  26
  27#define SAFFIRE_CLOCK_SOURCE_INTERNAL           0
  28#define SAFFIRE_CLOCK_SOURCE_SPDIF              1
  29
  30/* clock sources as returned from register of Saffire Pro 10 and 26 */
  31#define SAFFIREPRO_CLOCK_SOURCE_INTERNAL        0
  32#define SAFFIREPRO_CLOCK_SOURCE_SKIP            1 /* never used on hardware */
  33#define SAFFIREPRO_CLOCK_SOURCE_SPDIF           2
  34#define SAFFIREPRO_CLOCK_SOURCE_ADAT1           3 /* not used on s.pro. 10 */
  35#define SAFFIREPRO_CLOCK_SOURCE_ADAT2           4 /* not used on s.pro. 10 */
  36#define SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK       5
  37#define SAFFIREPRO_CLOCK_SOURCE_COUNT           6
  38
  39/* S/PDIF, ADAT1, ADAT2 is enabled or not. three quadlets */
  40#define SAFFIREPRO_ENABLE_DIG_IFACES            0x01a4
  41
  42/* saffirepro has its own parameter for sampling frequency */
  43#define SAFFIREPRO_RATE_NOREBOOT                0x01cc
  44/* index is the value for this register */
  45static const unsigned int rates[] = {
  46        [0] = 0,
  47        [1] = 44100,
  48        [2] = 48000,
  49        [3] = 88200,
  50        [4] = 96000,
  51        [5] = 176400,
  52        [6] = 192000
  53};
  54
  55/* saffire(no label)/saffire LE has metering */
  56#define SAFFIRE_OFFSET_METER                    0x0100
  57#define SAFFIRE_LE_OFFSET_METER                 0x0168
  58
  59static inline int
  60saffire_read_block(struct snd_bebob *bebob, u64 offset,
  61                   u32 *buf, unsigned int size)
  62{
  63        unsigned int i;
  64        int err;
  65        __be32 *tmp = (__be32 *)buf;
  66
  67        err =  snd_fw_transaction(bebob->unit, TCODE_READ_BLOCK_REQUEST,
  68                                  SAFFIRE_ADDRESS_BASE + offset,
  69                                  tmp, size, 0);
  70        if (err < 0)
  71                goto end;
  72
  73        for (i = 0; i < size / sizeof(u32); i++)
  74                buf[i] = be32_to_cpu(tmp[i]);
  75end:
  76        return err;
  77}
  78
  79static inline int
  80saffire_read_quad(struct snd_bebob *bebob, u64 offset, u32 *value)
  81{
  82        int err;
  83        __be32 tmp;
  84
  85        err = snd_fw_transaction(bebob->unit, TCODE_READ_QUADLET_REQUEST,
  86                                 SAFFIRE_ADDRESS_BASE + offset,
  87                                 &tmp, sizeof(__be32), 0);
  88        if (err < 0)
  89                goto end;
  90
  91        *value = be32_to_cpu(tmp);
  92end:
  93        return err;
  94}
  95
  96static inline int
  97saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value)
  98{
  99        __be32 data = cpu_to_be32(value);
 100
 101        return snd_fw_transaction(bebob->unit, TCODE_WRITE_QUADLET_REQUEST,
 102                                  SAFFIRE_ADDRESS_BASE + offset,
 103                                  &data, sizeof(__be32), 0);
 104}
 105
 106static enum snd_bebob_clock_type saffirepro_10_clk_src_types[] = {
 107        SND_BEBOB_CLOCK_TYPE_INTERNAL,
 108        SND_BEBOB_CLOCK_TYPE_EXTERNAL,  /* S/PDIF */
 109        SND_BEBOB_CLOCK_TYPE_EXTERNAL,  /* Word Clock */
 110};
 111static enum snd_bebob_clock_type saffirepro_26_clk_src_types[] = {
 112        SND_BEBOB_CLOCK_TYPE_INTERNAL,
 113        SND_BEBOB_CLOCK_TYPE_EXTERNAL,  /* S/PDIF */
 114        SND_BEBOB_CLOCK_TYPE_EXTERNAL,  /* ADAT1 */
 115        SND_BEBOB_CLOCK_TYPE_EXTERNAL,  /* ADAT2 */
 116        SND_BEBOB_CLOCK_TYPE_EXTERNAL,  /* Word Clock */
 117};
 118/* Value maps between registers and labels for SaffirePro 10/26. */
 119static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = {
 120        /* SaffirePro 10 */
 121        [0] = {
 122                [SAFFIREPRO_CLOCK_SOURCE_INTERNAL]  =  0,
 123                [SAFFIREPRO_CLOCK_SOURCE_SKIP]      = -1, /* not supported */
 124                [SAFFIREPRO_CLOCK_SOURCE_SPDIF]     =  1,
 125                [SAFFIREPRO_CLOCK_SOURCE_ADAT1]     = -1, /* not supported */
 126                [SAFFIREPRO_CLOCK_SOURCE_ADAT2]     = -1, /* not supported */
 127                [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] =  2,
 128        },
 129        /* SaffirePro 26 */
 130        [1] = {
 131                [SAFFIREPRO_CLOCK_SOURCE_INTERNAL]  =  0,
 132                [SAFFIREPRO_CLOCK_SOURCE_SKIP]      = -1, /* not supported */
 133                [SAFFIREPRO_CLOCK_SOURCE_SPDIF]     =  1,
 134                [SAFFIREPRO_CLOCK_SOURCE_ADAT1]     =  2,
 135                [SAFFIREPRO_CLOCK_SOURCE_ADAT2]     =  3,
 136                [SAFFIREPRO_CLOCK_SOURCE_WORDCLOCK] =  4,
 137        }
 138};
 139
 140static int
 141saffirepro_both_clk_freq_get(struct snd_bebob *bebob, unsigned int *rate)
 142{
 143        u32 id;
 144        int err;
 145
 146        err = saffire_read_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, &id);
 147        if (err < 0)
 148                goto end;
 149        if (id >= ARRAY_SIZE(rates))
 150                err = -EIO;
 151        else
 152                *rate = rates[id];
 153end:
 154        return err;
 155}
 156static int
 157saffirepro_both_clk_freq_set(struct snd_bebob *bebob, unsigned int rate)
 158{
 159        u32 id;
 160
 161        for (id = 0; id < ARRAY_SIZE(rates); id++) {
 162                if (rates[id] == rate)
 163                        break;
 164        }
 165        if (id == ARRAY_SIZE(rates))
 166                return -EINVAL;
 167
 168        return saffire_write_quad(bebob, SAFFIREPRO_RATE_NOREBOOT, id);
 169}
 170
 171/*
 172 * query hardware for current clock source, return our internally
 173 * used clock index in *id, depending on hardware.
 174 */
 175static int
 176saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
 177{
 178        int err;
 179        u32 value;       /* clock source read from hw register */
 180        const signed char *map;
 181
 182        err = saffire_read_quad(bebob, SAFFIREPRO_OFFSET_CLOCK_SOURCE, &value);
 183        if (err < 0)
 184                goto end;
 185
 186        /* depending on hardware, use a different mapping */
 187        if (bebob->spec->clock->types == saffirepro_10_clk_src_types)
 188                map = saffirepro_clk_maps[0];
 189        else
 190                map = saffirepro_clk_maps[1];
 191
 192        /* In a case that this driver cannot handle the value of register. */
 193        if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) {
 194                err = -EIO;
 195                goto end;
 196        }
 197
 198        *id = (unsigned int)map[value];
 199end:
 200        return err;
 201}
 202
 203const struct snd_bebob_spec saffire_le_spec;
 204static enum snd_bebob_clock_type saffire_both_clk_src_types[] = {
 205        SND_BEBOB_CLOCK_TYPE_INTERNAL,
 206        SND_BEBOB_CLOCK_TYPE_EXTERNAL,
 207};
 208static int
 209saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
 210{
 211        int err;
 212        u32 value;
 213
 214        err = saffire_read_quad(bebob, SAFFIRE_OFFSET_CLOCK_SOURCE, &value);
 215        if (err >= 0)
 216                *id = 0xff & value;
 217
 218        return err;
 219};
 220static const char *const saffire_le_meter_labels[] = {
 221        ANA_IN, ANA_IN, DIG_IN,
 222        ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
 223        STM_IN, STM_IN
 224};
 225static const char *const saffire_meter_labels[] = {
 226        ANA_IN, ANA_IN,
 227        STM_IN, STM_IN, STM_IN, STM_IN, STM_IN,
 228};
 229static int
 230saffire_meter_get(struct snd_bebob *bebob, u32 *buf, unsigned int size)
 231{
 232        const struct snd_bebob_meter_spec *spec = bebob->spec->meter;
 233        unsigned int channels;
 234        u64 offset;
 235        int err;
 236
 237        if (spec->labels == saffire_le_meter_labels)
 238                offset = SAFFIRE_LE_OFFSET_METER;
 239        else
 240                offset = SAFFIRE_OFFSET_METER;
 241
 242        channels = spec->num * 2;
 243        if (size < channels * sizeof(u32))
 244                return -EIO;
 245
 246        err = saffire_read_block(bebob, offset, buf, size);
 247        if (err >= 0 && spec->labels == saffire_le_meter_labels) {
 248                swap(buf[1], buf[3]);
 249                swap(buf[2], buf[3]);
 250                swap(buf[3], buf[4]);
 251
 252                swap(buf[7], buf[10]);
 253                swap(buf[8], buf[10]);
 254                swap(buf[9], buf[11]);
 255                swap(buf[11], buf[12]);
 256
 257                swap(buf[15], buf[16]);
 258        }
 259
 260        return err;
 261}
 262
 263static const struct snd_bebob_rate_spec saffirepro_both_rate_spec = {
 264        .get    = &saffirepro_both_clk_freq_get,
 265        .set    = &saffirepro_both_clk_freq_set,
 266};
 267/* Saffire Pro 26 I/O  */
 268static const struct snd_bebob_clock_spec saffirepro_26_clk_spec = {
 269        .num    = ARRAY_SIZE(saffirepro_26_clk_src_types),
 270        .types  = saffirepro_26_clk_src_types,
 271        .get    = &saffirepro_both_clk_src_get,
 272};
 273const struct snd_bebob_spec saffirepro_26_spec = {
 274        .clock  = &saffirepro_26_clk_spec,
 275        .rate   = &saffirepro_both_rate_spec,
 276        .meter  = NULL
 277};
 278/* Saffire Pro 10 I/O */
 279static const struct snd_bebob_clock_spec saffirepro_10_clk_spec = {
 280        .num    = ARRAY_SIZE(saffirepro_10_clk_src_types),
 281        .types  = saffirepro_10_clk_src_types,
 282        .get    = &saffirepro_both_clk_src_get,
 283};
 284const struct snd_bebob_spec saffirepro_10_spec = {
 285        .clock  = &saffirepro_10_clk_spec,
 286        .rate   = &saffirepro_both_rate_spec,
 287        .meter  = NULL
 288};
 289
 290static const struct snd_bebob_rate_spec saffire_both_rate_spec = {
 291        .get    = &snd_bebob_stream_get_rate,
 292        .set    = &snd_bebob_stream_set_rate,
 293};
 294static const struct snd_bebob_clock_spec saffire_both_clk_spec = {
 295        .num    = ARRAY_SIZE(saffire_both_clk_src_types),
 296        .types  = saffire_both_clk_src_types,
 297        .get    = &saffire_both_clk_src_get,
 298};
 299/* Saffire LE */
 300static const struct snd_bebob_meter_spec saffire_le_meter_spec = {
 301        .num    = ARRAY_SIZE(saffire_le_meter_labels),
 302        .labels = saffire_le_meter_labels,
 303        .get    = &saffire_meter_get,
 304};
 305const struct snd_bebob_spec saffire_le_spec = {
 306        .clock  = &saffire_both_clk_spec,
 307        .rate   = &saffire_both_rate_spec,
 308        .meter  = &saffire_le_meter_spec
 309};
 310/* Saffire */
 311static const struct snd_bebob_meter_spec saffire_meter_spec = {
 312        .num    = ARRAY_SIZE(saffire_meter_labels),
 313        .labels = saffire_meter_labels,
 314        .get    = &saffire_meter_get,
 315};
 316const struct snd_bebob_spec saffire_spec = {
 317        .clock  = &saffire_both_clk_spec,
 318        .rate   = &saffire_both_rate_spec,
 319        .meter  = &saffire_meter_spec
 320};
 321