forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/sound/pci/hda/hda_generic.c
....@@ -1,23 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Universal Interface for Intel High Definition Audio Codec
34 *
45 * Generic widget tree parser
56 *
67 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
7
- *
8
- * This driver is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version.
12
- *
13
- * This driver is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public License
19
- * along with this program; if not, write to the Free Software
20
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
218 */
229
2310 #include <linux/init.h>
....@@ -29,10 +16,11 @@
2916 #include <linux/string.h>
3017 #include <linux/bitops.h>
3118 #include <linux/module.h>
19
+#include <linux/leds.h>
3220 #include <sound/core.h>
3321 #include <sound/jack.h>
3422 #include <sound/tlv.h>
35
-#include "hda_codec.h"
23
+#include <sound/hda_codec.h>
3624 #include "hda_local.h"
3725 #include "hda_auto_parser.h"
3826 #include "hda_jack.h"
....@@ -103,6 +91,12 @@
10391 free_kctls(spec);
10492 snd_array_free(&spec->paths);
10593 snd_array_free(&spec->loopback_list);
94
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
95
+ if (spec->led_cdevs[LED_AUDIO_MUTE])
96
+ led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
97
+ if (spec->led_cdevs[LED_AUDIO_MICMUTE])
98
+ led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
99
+#endif
106100 }
107101
108102 /*
....@@ -3913,6 +3907,73 @@
39133907 return 0;
39143908 }
39153909
3910
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
3911
+/*
3912
+ * vmaster mute LED hook helpers
3913
+ */
3914
+
3915
+static int create_mute_led_cdev(struct hda_codec *codec,
3916
+ int (*callback)(struct led_classdev *,
3917
+ enum led_brightness),
3918
+ bool micmute)
3919
+{
3920
+ struct hda_gen_spec *spec = codec->spec;
3921
+ struct led_classdev *cdev;
3922
+ int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
3923
+ int err;
3924
+
3925
+ cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
3926
+ if (!cdev)
3927
+ return -ENOMEM;
3928
+
3929
+ cdev->name = micmute ? "hda::micmute" : "hda::mute";
3930
+ cdev->max_brightness = 1;
3931
+ cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
3932
+ cdev->brightness_set_blocking = callback;
3933
+ cdev->brightness = ledtrig_audio_get(idx);
3934
+ cdev->flags = LED_CORE_SUSPENDRESUME;
3935
+
3936
+ err = led_classdev_register(&codec->core.dev, cdev);
3937
+ if (err < 0)
3938
+ return err;
3939
+ spec->led_cdevs[idx] = cdev;
3940
+ return 0;
3941
+}
3942
+
3943
+static void vmaster_update_mute_led(void *private_data, int enabled)
3944
+{
3945
+ ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
3946
+}
3947
+
3948
+/**
3949
+ * snd_dha_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
3950
+ * @codec: the HDA codec
3951
+ * @callback: the callback for LED classdev brightness_set_blocking
3952
+ */
3953
+int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
3954
+ int (*callback)(struct led_classdev *,
3955
+ enum led_brightness))
3956
+{
3957
+ struct hda_gen_spec *spec = codec->spec;
3958
+ int err;
3959
+
3960
+ if (callback) {
3961
+ err = create_mute_led_cdev(codec, callback, false);
3962
+ if (err) {
3963
+ codec_warn(codec, "failed to create a mute LED cdev\n");
3964
+ return err;
3965
+ }
3966
+ }
3967
+
3968
+ if (spec->vmaster_mute.hook)
3969
+ codec_err(codec, "vmaster hook already present before cdev!\n");
3970
+
3971
+ spec->vmaster_mute.hook = vmaster_update_mute_led;
3972
+ spec->vmaster_mute_enum = 1;
3973
+ return 0;
3974
+}
3975
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
3976
+
39163977 /*
39173978 * mic mute LED hook helpers
39183979 */
....@@ -3947,8 +4008,8 @@
39474008 if (val == spec->micmute_led.led_value)
39484009 return;
39494010 spec->micmute_led.led_value = val;
3950
- if (spec->micmute_led.update)
3951
- spec->micmute_led.update(codec);
4011
+ ledtrig_audio_set(LED_AUDIO_MICMUTE,
4012
+ spec->micmute_led.led_value ? LED_ON : LED_OFF);
39524013 }
39534014
39544015 static void update_micmute_led(struct hda_codec *codec,
....@@ -4020,20 +4081,8 @@
40204081 .put = micmute_led_mode_put,
40214082 };
40224083
4023
-/**
4024
- * snd_hda_gen_add_micmute_led - helper for setting up mic mute LED hook
4025
- * @codec: the HDA codec
4026
- * @hook: the callback for updating LED
4027
- *
4028
- * Called from the codec drivers for offering the mic mute LED controls.
4029
- * When established, it sets up cap_sync_hook and triggers the callback at
4030
- * each time when the capture mixer switch changes. The callback is supposed
4031
- * to update the LED accordingly.
4032
- *
4033
- * Returns 0 if the hook is established or a negative error code.
4034
- */
4035
-int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
4036
- void (*hook)(struct hda_codec *))
4084
+/* Set up the capture sync hook for controlling the mic-mute LED */
4085
+static int add_micmute_led_hook(struct hda_codec *codec)
40374086 {
40384087 struct hda_gen_spec *spec = codec->spec;
40394088
....@@ -4041,13 +4090,44 @@
40414090 spec->micmute_led.capture = 0;
40424091 spec->micmute_led.led_value = -1;
40434092 spec->micmute_led.old_hook = spec->cap_sync_hook;
4044
- spec->micmute_led.update = hook;
40454093 spec->cap_sync_hook = update_micmute_led;
40464094 if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
40474095 return -ENOMEM;
40484096 return 0;
40494097 }
4050
-EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
4098
+
4099
+/**
4100
+ * snd_dha_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
4101
+ * @codec: the HDA codec
4102
+ * @callback: the callback for LED classdev brightness_set_blocking
4103
+ *
4104
+ * Called from the codec drivers for offering the mic mute LED controls.
4105
+ * This creates a LED classdev and sets up the cap_sync_hook that is called at
4106
+ * each time when the capture mixer switch changes.
4107
+ *
4108
+ * When NULL is passed to @callback, no classdev is created but only the
4109
+ * LED-trigger is set up.
4110
+ *
4111
+ * Returns 0 or a negative error.
4112
+ */
4113
+int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
4114
+ int (*callback)(struct led_classdev *,
4115
+ enum led_brightness))
4116
+{
4117
+ int err;
4118
+
4119
+ if (callback) {
4120
+ err = create_mute_led_cdev(codec, callback, true);
4121
+ if (err) {
4122
+ codec_warn(codec, "failed to create a mic-mute LED cdev\n");
4123
+ return err;
4124
+ }
4125
+ }
4126
+
4127
+ return add_micmute_led_hook(codec);
4128
+}
4129
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
4130
+#endif /* CONFIG_SND_HDA_GENERIC_LEDS */
40514131
40524132 /*
40534133 * parse digital I/Os and set up NIDs in BIOS auto-parse mode
....@@ -4059,7 +4139,7 @@
40594139 int i, nums;
40604140 hda_nid_t dig_nid, pin;
40614141
4062
- /* support multiple SPDIFs; the secondary is set up as a slave */
4142
+ /* support multiple SPDIFs; the secondary is set up as a follower */
40634143 nums = 0;
40644144 for (i = 0; i < spec->autocfg.dig_outs; i++) {
40654145 pin = spec->autocfg.dig_out_pins[i];
....@@ -4078,10 +4158,10 @@
40784158 spec->multiout.dig_out_nid = dig_nid;
40794159 spec->dig_out_type = spec->autocfg.dig_out_type[0];
40804160 } else {
4081
- spec->multiout.slave_dig_outs = spec->slave_dig_outs;
4082
- if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
4161
+ spec->multiout.follower_dig_outs = spec->follower_dig_outs;
4162
+ if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1)
40834163 break;
4084
- spec->slave_dig_outs[nums - 1] = dig_nid;
4164
+ spec->follower_dig_outs[nums - 1] = dig_nid;
40854165 }
40864166 nums++;
40874167 }
....@@ -4397,7 +4477,7 @@
43974477 */
43984478
43994479 /* check each pin in the given array; returns true if any of them is plugged */
4400
-static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
4480
+static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins)
44014481 {
44024482 int i;
44034483 bool present = false;
....@@ -4416,7 +4496,7 @@
44164496 }
44174497
44184498 /* standard HP/line-out auto-mute helper */
4419
-static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
4499
+static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins,
44204500 int *paths, bool mute)
44214501 {
44224502 struct hda_gen_spec *spec = codec->spec;
....@@ -4536,7 +4616,7 @@
45364616 else
45374617 snd_hda_gen_update_outputs(codec);
45384618
4539
- /* sync the whole vmaster slaves to reflect the new auto-mute status */
4619
+ /* sync the whole vmaster followers to reflect the new auto-mute status */
45404620 if (spec->auto_mute_via_amp && !codec->bus->shutdown)
45414621 snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
45424622 }
....@@ -5180,8 +5260,8 @@
51805260 * Build control elements
51815261 */
51825262
5183
-/* slave controls for virtual master */
5184
-static const char * const slave_pfxs[] = {
5263
+/* follower controls for virtual master */
5264
+static const char * const follower_pfxs[] = {
51855265 "Front", "Surround", "Center", "LFE", "Side",
51865266 "Headphone", "Speaker", "Mono", "Line Out",
51875267 "CLFE", "Bass Speaker", "PCM",
....@@ -5233,7 +5313,7 @@
52335313 if (!spec->no_analog && !spec->suppress_vmaster &&
52345314 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
52355315 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
5236
- spec->vmaster_tlv, slave_pfxs,
5316
+ spec->vmaster_tlv, follower_pfxs,
52375317 "Playback Volume");
52385318 if (err < 0)
52395319 return err;
....@@ -5241,7 +5321,7 @@
52415321 if (!spec->no_analog && !spec->suppress_vmaster &&
52425322 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
52435323 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
5244
- NULL, slave_pfxs,
5324
+ NULL, follower_pfxs,
52455325 "Playback Switch",
52465326 true, &spec->vmaster_mute.sw_kctl);
52475327 if (err < 0)
....@@ -5756,7 +5836,7 @@
57565836 spec->stream_name_digital);
57575837 if (!info)
57585838 return -ENOMEM;
5759
- codec->slave_dig_outs = spec->multiout.slave_dig_outs;
5839
+ codec->follower_dig_outs = spec->multiout.follower_dig_outs;
57605840 spec->pcm_rec[1] = info;
57615841 if (spec->dig_out_type)
57625842 info->pcm_type = spec->dig_out_type;
....@@ -6023,7 +6103,7 @@
60236103 /* call init functions of standard auto-mute helpers */
60246104 update_automute_all(codec);
60256105
6026
- regcache_sync(codec->core.regmap);
6106
+ snd_hda_regmap_sync(codec);
60276107
60286108 if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
60296109 snd_hda_sync_vmaster_hook(&spec->vmaster_mute);