linux/sound/hda/hdac_regmap.c
<<
>>
Prefs
   1/*
   2 * Regmap support for HD-audio verbs
   3 *
   4 * A virtual register is translated to one or more hda verbs for write,
   5 * vice versa for read.
   6 *
   7 * A few limitations:
   8 * - Provided for not all verbs but only subset standard non-volatile verbs.
   9 * - For reading, only AC_VERB_GET_* variants can be used.
  10 * - For writing, mapped to the *corresponding* AC_VERB_SET_* variants,
  11 *   so can't handle asymmetric verbs for read and write
  12 */
  13
  14#include <linux/slab.h>
  15#include <linux/device.h>
  16#include <linux/regmap.h>
  17#include <linux/export.h>
  18#include <linux/pm.h>
  19#include <linux/pm_runtime.h>
  20#include <sound/core.h>
  21#include <sound/hdaudio.h>
  22#include <sound/hda_regmap.h>
  23
  24static int codec_pm_lock(struct hdac_device *codec)
  25{
  26        return snd_hdac_keep_power_up(codec);
  27}
  28
  29static void codec_pm_unlock(struct hdac_device *codec, int lock)
  30{
  31        if (lock == 1)
  32                snd_hdac_power_down_pm(codec);
  33}
  34
  35#define get_verb(reg)   (((reg) >> 8) & 0xfff)
  36
  37static bool hda_volatile_reg(struct device *dev, unsigned int reg)
  38{
  39        struct hdac_device *codec = dev_to_hdac_dev(dev);
  40        unsigned int verb = get_verb(reg);
  41
  42        switch (verb) {
  43        case AC_VERB_GET_PROC_COEF:
  44                return !codec->cache_coef;
  45        case AC_VERB_GET_COEF_INDEX:
  46        case AC_VERB_GET_PROC_STATE:
  47        case AC_VERB_GET_POWER_STATE:
  48        case AC_VERB_GET_PIN_SENSE:
  49        case AC_VERB_GET_HDMI_DIP_SIZE:
  50        case AC_VERB_GET_HDMI_ELDD:
  51        case AC_VERB_GET_HDMI_DIP_INDEX:
  52        case AC_VERB_GET_HDMI_DIP_DATA:
  53        case AC_VERB_GET_HDMI_DIP_XMIT:
  54        case AC_VERB_GET_HDMI_CP_CTRL:
  55        case AC_VERB_GET_HDMI_CHAN_SLOT:
  56        case AC_VERB_GET_DEVICE_SEL:
  57        case AC_VERB_GET_DEVICE_LIST:   /* read-only volatile */
  58                return true;
  59        }
  60
  61        return false;
  62}
  63
  64static bool hda_writeable_reg(struct device *dev, unsigned int reg)
  65{
  66        struct hdac_device *codec = dev_to_hdac_dev(dev);
  67        unsigned int verb = get_verb(reg);
  68        const unsigned int *v;
  69        int i;
  70
  71        snd_array_for_each(&codec->vendor_verbs, i, v) {
  72                if (verb == *v)
  73                        return true;
  74        }
  75
  76        if (codec->caps_overwriting)
  77                return true;
  78
  79        switch (verb & 0xf00) {
  80        case AC_VERB_GET_STREAM_FORMAT:
  81        case AC_VERB_GET_AMP_GAIN_MUTE:
  82                return true;
  83        case AC_VERB_GET_PROC_COEF:
  84                return codec->cache_coef;
  85        case 0xf00:
  86                break;
  87        default:
  88                return false;
  89        }
  90
  91        switch (verb) {
  92        case AC_VERB_GET_CONNECT_SEL:
  93        case AC_VERB_GET_SDI_SELECT:
  94        case AC_VERB_GET_PIN_WIDGET_CONTROL:
  95        case AC_VERB_GET_UNSOLICITED_RESPONSE: /* only as SET_UNSOLICITED_ENABLE */
  96        case AC_VERB_GET_BEEP_CONTROL:
  97        case AC_VERB_GET_EAPD_BTLENABLE:
  98        case AC_VERB_GET_DIGI_CONVERT_1:
  99        case AC_VERB_GET_DIGI_CONVERT_2: /* only for beep control */
 100        case AC_VERB_GET_VOLUME_KNOB_CONTROL:
 101        case AC_VERB_GET_GPIO_MASK:
 102        case AC_VERB_GET_GPIO_DIRECTION:
 103        case AC_VERB_GET_GPIO_DATA: /* not for volatile read */
 104        case AC_VERB_GET_GPIO_WAKE_MASK:
 105        case AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK:
 106        case AC_VERB_GET_GPIO_STICKY_MASK:
 107                return true;
 108        }
 109
 110        return false;
 111}
 112
 113static bool hda_readable_reg(struct device *dev, unsigned int reg)
 114{
 115        struct hdac_device *codec = dev_to_hdac_dev(dev);
 116        unsigned int verb = get_verb(reg);
 117
 118        if (codec->caps_overwriting)
 119                return true;
 120
 121        switch (verb) {
 122        case AC_VERB_PARAMETERS:
 123        case AC_VERB_GET_CONNECT_LIST:
 124        case AC_VERB_GET_SUBSYSTEM_ID:
 125                return true;
 126        /* below are basically writable, but disabled for reducing unnecessary
 127         * writes at sync
 128         */
 129        case AC_VERB_GET_CONFIG_DEFAULT: /* usually just read */
 130        case AC_VERB_GET_CONV: /* managed in PCM code */
 131        case AC_VERB_GET_CVT_CHAN_COUNT: /* managed in HDMI CA code */
 132                return true;
 133        }
 134
 135        return hda_writeable_reg(dev, reg);
 136}
 137
 138/*
 139 * Stereo amp pseudo register:
 140 * for making easier to handle the stereo volume control, we provide a
 141 * fake register to deal both left and right channels by a single
 142 * (pseudo) register access.  A verb consisting of SET_AMP_GAIN with
 143 * *both* SET_LEFT and SET_RIGHT bits takes a 16bit value, the lower 8bit
 144 * for the left and the upper 8bit for the right channel.
 145 */
 146static bool is_stereo_amp_verb(unsigned int reg)
 147{
 148        if (((reg >> 8) & 0x700) != AC_VERB_SET_AMP_GAIN_MUTE)
 149                return false;
 150        return (reg & (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT)) ==
 151                (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
 152}
 153
 154/* read a pseudo stereo amp register (16bit left+right) */
 155static int hda_reg_read_stereo_amp(struct hdac_device *codec,
 156                                   unsigned int reg, unsigned int *val)
 157{
 158        unsigned int left, right;
 159        int err;
 160
 161        reg &= ~(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
 162        err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_LEFT, 0, &left);
 163        if (err < 0)
 164                return err;
 165        err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_RIGHT, 0, &right);
 166        if (err < 0)
 167                return err;
 168        *val = left | (right << 8);
 169        return 0;
 170}
 171
 172/* write a pseudo stereo amp register (16bit left+right) */
 173static int hda_reg_write_stereo_amp(struct hdac_device *codec,
 174                                    unsigned int reg, unsigned int val)
 175{
 176        int err;
 177        unsigned int verb, left, right;
 178
 179        verb = AC_VERB_SET_AMP_GAIN_MUTE << 8;
 180        if (reg & AC_AMP_GET_OUTPUT)
 181                verb |= AC_AMP_SET_OUTPUT;
 182        else
 183                verb |= AC_AMP_SET_INPUT | ((reg & 0xf) << 8);
 184        reg = (reg & ~0xfffff) | verb;
 185
 186        left = val & 0xff;
 187        right = (val >> 8) & 0xff;
 188        if (left == right) {
 189                reg |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
 190                return snd_hdac_exec_verb(codec, reg | left, 0, NULL);
 191        }
 192
 193        err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_LEFT | left, 0, NULL);
 194        if (err < 0)
 195                return err;
 196        err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_RIGHT | right, 0, NULL);
 197        if (err < 0)
 198                return err;
 199        return 0;
 200}
 201
 202/* read a pseudo coef register (16bit) */
 203static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg,
 204                             unsigned int *val)
 205{
 206        unsigned int verb;
 207        int err;
 208
 209        if (!codec->cache_coef)
 210                return -EINVAL;
 211        /* LSB 8bit = coef index */
 212        verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
 213        err = snd_hdac_exec_verb(codec, verb, 0, NULL);
 214        if (err < 0)
 215                return err;
 216        verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8);
 217        return snd_hdac_exec_verb(codec, verb, 0, val);
 218}
 219
 220/* write a pseudo coef register (16bit) */
 221static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg,
 222                              unsigned int val)
 223{
 224        unsigned int verb;
 225        int err;
 226
 227        if (!codec->cache_coef)
 228                return -EINVAL;
 229        /* LSB 8bit = coef index */
 230        verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
 231        err = snd_hdac_exec_verb(codec, verb, 0, NULL);
 232        if (err < 0)
 233                return err;
 234        verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) |
 235                (val & 0xffff);
 236        return snd_hdac_exec_verb(codec, verb, 0, NULL);
 237}
 238
 239static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
 240{
 241        struct hdac_device *codec = context;
 242        int verb = get_verb(reg);
 243        int err;
 244        int pm_lock = 0;
 245
 246        if (verb != AC_VERB_GET_POWER_STATE) {
 247                pm_lock = codec_pm_lock(codec);
 248                if (pm_lock < 0)
 249                        return -EAGAIN;
 250        }
 251        reg |= (codec->addr << 28);
 252        if (is_stereo_amp_verb(reg)) {
 253                err = hda_reg_read_stereo_amp(codec, reg, val);
 254                goto out;
 255        }
 256        if (verb == AC_VERB_GET_PROC_COEF) {
 257                err = hda_reg_read_coef(codec, reg, val);
 258                goto out;
 259        }
 260        if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE)
 261                reg &= ~AC_AMP_FAKE_MUTE;
 262
 263        err = snd_hdac_exec_verb(codec, reg, 0, val);
 264        if (err < 0)
 265                goto out;
 266        /* special handling for asymmetric reads */
 267        if (verb == AC_VERB_GET_POWER_STATE) {
 268                if (*val & AC_PWRST_ERROR)
 269                        *val = -1;
 270                else /* take only the actual state */
 271                        *val = (*val >> 4) & 0x0f;
 272        }
 273 out:
 274        codec_pm_unlock(codec, pm_lock);
 275        return err;
 276}
 277
 278static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
 279{
 280        struct hdac_device *codec = context;
 281        unsigned int verb;
 282        int i, bytes, err;
 283        int pm_lock = 0;
 284
 285        if (codec->caps_overwriting)
 286                return 0;
 287
 288        reg &= ~0x00080000U; /* drop GET bit */
 289        reg |= (codec->addr << 28);
 290        verb = get_verb(reg);
 291
 292        if (verb != AC_VERB_SET_POWER_STATE) {
 293                pm_lock = codec_pm_lock(codec);
 294                if (pm_lock < 0)
 295                        return codec->lazy_cache ? 0 : -EAGAIN;
 296        }
 297
 298        if (is_stereo_amp_verb(reg)) {
 299                err = hda_reg_write_stereo_amp(codec, reg, val);
 300                goto out;
 301        }
 302
 303        if (verb == AC_VERB_SET_PROC_COEF) {
 304                err = hda_reg_write_coef(codec, reg, val);
 305                goto out;
 306        }
 307
 308        switch (verb & 0xf00) {
 309        case AC_VERB_SET_AMP_GAIN_MUTE:
 310                if ((reg & AC_AMP_FAKE_MUTE) && (val & AC_AMP_MUTE))
 311                        val = 0;
 312                verb = AC_VERB_SET_AMP_GAIN_MUTE;
 313                if (reg & AC_AMP_GET_LEFT)
 314                        verb |= AC_AMP_SET_LEFT >> 8;
 315                else
 316                        verb |= AC_AMP_SET_RIGHT >> 8;
 317                if (reg & AC_AMP_GET_OUTPUT) {
 318                        verb |= AC_AMP_SET_OUTPUT >> 8;
 319                } else {
 320                        verb |= AC_AMP_SET_INPUT >> 8;
 321                        verb |= reg & 0xf;
 322                }
 323                break;
 324        }
 325
 326        switch (verb) {
 327        case AC_VERB_SET_DIGI_CONVERT_1:
 328                bytes = 2;
 329                break;
 330        case AC_VERB_SET_CONFIG_DEFAULT_BYTES_0:
 331                bytes = 4;
 332                break;
 333        default:
 334                bytes = 1;
 335                break;
 336        }
 337
 338        for (i = 0; i < bytes; i++) {
 339                reg &= ~0xfffff;
 340                reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);
 341                err = snd_hdac_exec_verb(codec, reg, 0, NULL);
 342                if (err < 0)
 343                        goto out;
 344        }
 345
 346 out:
 347        codec_pm_unlock(codec, pm_lock);
 348        return err;
 349}
 350
 351static const struct regmap_config hda_regmap_cfg = {
 352        .name = "hdaudio",
 353        .reg_bits = 32,
 354        .val_bits = 32,
 355        .max_register = 0xfffffff,
 356        .writeable_reg = hda_writeable_reg,
 357        .readable_reg = hda_readable_reg,
 358        .volatile_reg = hda_volatile_reg,
 359        .cache_type = REGCACHE_RBTREE,
 360        .reg_read = hda_reg_read,
 361        .reg_write = hda_reg_write,
 362        .use_single_rw = true,
 363};
 364
 365/**
 366 * snd_hdac_regmap_init - Initialize regmap for HDA register accesses
 367 * @codec: the codec object
 368 *
 369 * Returns zero for success or a negative error code.
 370 */
 371int snd_hdac_regmap_init(struct hdac_device *codec)
 372{
 373        struct regmap *regmap;
 374
 375        regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg);
 376        if (IS_ERR(regmap))
 377                return PTR_ERR(regmap);
 378        codec->regmap = regmap;
 379        snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8);
 380        return 0;
 381}
 382EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);
 383
 384/**
 385 * snd_hdac_regmap_init - Release the regmap from HDA codec
 386 * @codec: the codec object
 387 */
 388void snd_hdac_regmap_exit(struct hdac_device *codec)
 389{
 390        if (codec->regmap) {
 391                regmap_exit(codec->regmap);
 392                codec->regmap = NULL;
 393                snd_array_free(&codec->vendor_verbs);
 394        }
 395}
 396EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit);
 397
 398/**
 399 * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap
 400 * @codec: the codec object
 401 * @verb: verb to allow accessing via regmap
 402 *
 403 * Returns zero for success or a negative error code.
 404 */
 405int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
 406                                    unsigned int verb)
 407{
 408        unsigned int *p = snd_array_new(&codec->vendor_verbs);
 409
 410        if (!p)
 411                return -ENOMEM;
 412        *p = verb | 0x800; /* set GET bit */
 413        return 0;
 414}
 415EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
 416
 417/*
 418 * helper functions
 419 */
 420
 421/* write a pseudo-register value (w/o power sequence) */
 422static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
 423                         unsigned int val)
 424{
 425        if (!codec->regmap)
 426                return hda_reg_write(codec, reg, val);
 427        else
 428                return regmap_write(codec->regmap, reg, val);
 429}
 430
 431/**
 432 * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
 433 * @codec: the codec object
 434 * @reg: pseudo register
 435 * @val: value to write
 436 *
 437 * Returns zero if successful or a negative error code.
 438 */
 439int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
 440                              unsigned int val)
 441{
 442        int err;
 443
 444        err = reg_raw_write(codec, reg, val);
 445        if (err == -EAGAIN) {
 446                err = snd_hdac_power_up_pm(codec);
 447                if (err >= 0)
 448                        err = reg_raw_write(codec, reg, val);
 449                snd_hdac_power_down_pm(codec);
 450        }
 451        return err;
 452}
 453EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
 454
 455static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
 456                        unsigned int *val, bool uncached)
 457{
 458        if (uncached || !codec->regmap)
 459                return hda_reg_read(codec, reg, val);
 460        else
 461                return regmap_read(codec->regmap, reg, val);
 462}
 463
 464static int __snd_hdac_regmap_read_raw(struct hdac_device *codec,
 465                                      unsigned int reg, unsigned int *val,
 466                                      bool uncached)
 467{
 468        int err;
 469
 470        err = reg_raw_read(codec, reg, val, uncached);
 471        if (err == -EAGAIN) {
 472                err = snd_hdac_power_up_pm(codec);
 473                if (err >= 0)
 474                        err = reg_raw_read(codec, reg, val, uncached);
 475                snd_hdac_power_down_pm(codec);
 476        }
 477        return err;
 478}
 479
 480/**
 481 * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt
 482 * @codec: the codec object
 483 * @reg: pseudo register
 484 * @val: pointer to store the read value
 485 *
 486 * Returns zero if successful or a negative error code.
 487 */
 488int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
 489                             unsigned int *val)
 490{
 491        return __snd_hdac_regmap_read_raw(codec, reg, val, false);
 492}
 493EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw);
 494
 495/* Works like snd_hdac_regmap_read_raw(), but this doesn't read from the
 496 * cache but always via hda verbs.
 497 */
 498int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec,
 499                                      unsigned int reg, unsigned int *val)
 500{
 501        return __snd_hdac_regmap_read_raw(codec, reg, val, true);
 502}
 503
 504/**
 505 * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
 506 * @codec: the codec object
 507 * @reg: pseudo register
 508 * @mask: bit mask to udpate
 509 * @val: value to update
 510 *
 511 * Returns zero if successful or a negative error code.
 512 */
 513int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
 514                               unsigned int mask, unsigned int val)
 515{
 516        unsigned int orig;
 517        int err;
 518
 519        val &= mask;
 520        err = snd_hdac_regmap_read_raw(codec, reg, &orig);
 521        if (err < 0)
 522                return err;
 523        val |= orig & ~mask;
 524        if (val == orig)
 525                return 0;
 526        err = snd_hdac_regmap_write_raw(codec, reg, val);
 527        if (err < 0)
 528                return err;
 529        return 1;
 530}
 531EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);
 532