hc
2024-05-10 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb
kernel/sound/hda/hdac_regmap.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Regmap support for HD-audio verbs
34 *
....@@ -20,6 +21,7 @@
2021 #include <sound/core.h>
2122 #include <sound/hdaudio.h>
2223 #include <sound/hda_regmap.h>
24
+#include "local.h"
2325
2426 static int codec_pm_lock(struct hdac_device *codec)
2527 {
....@@ -359,7 +361,9 @@
359361 .cache_type = REGCACHE_RBTREE,
360362 .reg_read = hda_reg_read,
361363 .reg_write = hda_reg_write,
362
- .use_single_rw = true,
364
+ .use_single_read = true,
365
+ .use_single_write = true,
366
+ .disable_locking = true,
363367 };
364368
365369 /**
....@@ -422,11 +426,28 @@
422426 static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
423427 unsigned int val)
424428 {
429
+ int err;
430
+
431
+ mutex_lock(&codec->regmap_lock);
425432 if (!codec->regmap)
426
- return hda_reg_write(codec, reg, val);
433
+ err = hda_reg_write(codec, reg, val);
427434 else
428
- return regmap_write(codec->regmap, reg, val);
435
+ err = regmap_write(codec->regmap, reg, val);
436
+ mutex_unlock(&codec->regmap_lock);
437
+ return err;
429438 }
439
+
440
+/* a helper macro to call @func_call; retry with power-up if failed */
441
+#define CALL_RAW_FUNC(codec, func_call) \
442
+ ({ \
443
+ int _err = func_call; \
444
+ if (_err == -EAGAIN) { \
445
+ _err = snd_hdac_power_up_pm(codec); \
446
+ if (_err >= 0) \
447
+ _err = func_call; \
448
+ snd_hdac_power_down_pm(codec); \
449
+ } \
450
+ _err;})
430451
431452 /**
432453 * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
....@@ -439,42 +460,29 @@
439460 int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
440461 unsigned int val)
441462 {
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;
463
+ return CALL_RAW_FUNC(codec, reg_raw_write(codec, reg, val));
452464 }
453465 EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
454466
455467 static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
456468 unsigned int *val, bool uncached)
457469 {
470
+ int err;
471
+
472
+ mutex_lock(&codec->regmap_lock);
458473 if (uncached || !codec->regmap)
459
- return hda_reg_read(codec, reg, val);
474
+ err = hda_reg_read(codec, reg, val);
460475 else
461
- return regmap_read(codec->regmap, reg, val);
476
+ err = regmap_read(codec->regmap, reg, val);
477
+ mutex_unlock(&codec->regmap_lock);
478
+ return err;
462479 }
463480
464481 static int __snd_hdac_regmap_read_raw(struct hdac_device *codec,
465482 unsigned int reg, unsigned int *val,
466483 bool uncached)
467484 {
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;
485
+ return CALL_RAW_FUNC(codec, reg_raw_read(codec, reg, val, uncached));
478486 }
479487
480488 /**
....@@ -501,11 +509,40 @@
501509 return __snd_hdac_regmap_read_raw(codec, reg, val, true);
502510 }
503511
512
+static int reg_raw_update(struct hdac_device *codec, unsigned int reg,
513
+ unsigned int mask, unsigned int val)
514
+{
515
+ unsigned int orig;
516
+ bool change;
517
+ int err;
518
+
519
+ mutex_lock(&codec->regmap_lock);
520
+ if (codec->regmap) {
521
+ err = regmap_update_bits_check(codec->regmap, reg, mask, val,
522
+ &change);
523
+ if (!err)
524
+ err = change ? 1 : 0;
525
+ } else {
526
+ err = hda_reg_read(codec, reg, &orig);
527
+ if (!err) {
528
+ val &= mask;
529
+ val |= orig & ~mask;
530
+ if (val != orig) {
531
+ err = hda_reg_write(codec, reg, val);
532
+ if (!err)
533
+ err = 1;
534
+ }
535
+ }
536
+ }
537
+ mutex_unlock(&codec->regmap_lock);
538
+ return err;
539
+}
540
+
504541 /**
505542 * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
506543 * @codec: the codec object
507544 * @reg: pseudo register
508
- * @mask: bit mask to udpate
545
+ * @mask: bit mask to update
509546 * @val: value to update
510547 *
511548 * Returns zero if successful or a negative error code.
....@@ -513,19 +550,56 @@
513550 int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
514551 unsigned int mask, unsigned int val)
515552 {
553
+ return CALL_RAW_FUNC(codec, reg_raw_update(codec, reg, mask, val));
554
+}
555
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);
556
+
557
+static int reg_raw_update_once(struct hdac_device *codec, unsigned int reg,
558
+ unsigned int mask, unsigned int val)
559
+{
516560 unsigned int orig;
517561 int err;
518562
519
- val &= mask;
520
- err = snd_hdac_regmap_read_raw(codec, reg, &orig);
563
+ if (!codec->regmap)
564
+ return reg_raw_update(codec, reg, mask, val);
565
+
566
+ mutex_lock(&codec->regmap_lock);
567
+ regcache_cache_only(codec->regmap, true);
568
+ err = regmap_read(codec->regmap, reg, &orig);
569
+ regcache_cache_only(codec->regmap, false);
521570 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;
571
+ err = regmap_update_bits(codec->regmap, reg, mask, val);
572
+ mutex_unlock(&codec->regmap_lock);
573
+ return err;
530574 }
531
-EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);
575
+
576
+/**
577
+ * snd_hdac_regmap_update_raw_once - initialize the register value only once
578
+ * @codec: the codec object
579
+ * @reg: pseudo register
580
+ * @mask: bit mask to update
581
+ * @val: value to update
582
+ *
583
+ * Performs the update of the register bits only once when the register
584
+ * hasn't been initialized yet. Used in HD-audio legacy driver.
585
+ * Returns zero if successful or a negative error code
586
+ */
587
+int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg,
588
+ unsigned int mask, unsigned int val)
589
+{
590
+ return CALL_RAW_FUNC(codec, reg_raw_update_once(codec, reg, mask, val));
591
+}
592
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw_once);
593
+
594
+/**
595
+ * snd_hdac_regmap_sync - sync out the cached values for PM resume
596
+ * @codec: the codec object
597
+ */
598
+void snd_hdac_regmap_sync(struct hdac_device *codec)
599
+{
600
+ mutex_lock(&codec->regmap_lock);
601
+ if (codec->regmap)
602
+ regcache_sync(codec->regmap);
603
+ mutex_unlock(&codec->regmap_lock);
604
+}
605
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_sync);