.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Universal Interface for Intel High Definition Audio Codec |
---|
3 | 4 | * |
---|
4 | 5 | * Generic widget tree parser |
---|
5 | 6 | * |
---|
6 | 7 | * 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 |
---|
21 | 8 | */ |
---|
22 | 9 | |
---|
23 | 10 | #include <linux/init.h> |
---|
.. | .. |
---|
29 | 16 | #include <linux/string.h> |
---|
30 | 17 | #include <linux/bitops.h> |
---|
31 | 18 | #include <linux/module.h> |
---|
| 19 | +#include <linux/leds.h> |
---|
32 | 20 | #include <sound/core.h> |
---|
33 | 21 | #include <sound/jack.h> |
---|
34 | 22 | #include <sound/tlv.h> |
---|
35 | | -#include "hda_codec.h" |
---|
| 23 | +#include <sound/hda_codec.h> |
---|
36 | 24 | #include "hda_local.h" |
---|
37 | 25 | #include "hda_auto_parser.h" |
---|
38 | 26 | #include "hda_jack.h" |
---|
.. | .. |
---|
103 | 91 | free_kctls(spec); |
---|
104 | 92 | snd_array_free(&spec->paths); |
---|
105 | 93 | 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 |
---|
106 | 100 | } |
---|
107 | 101 | |
---|
108 | 102 | /* |
---|
.. | .. |
---|
1159 | 1153 | return path && path->ctls[ctl_type]; |
---|
1160 | 1154 | } |
---|
1161 | 1155 | |
---|
1162 | | -static const char * const channel_name[4] = { |
---|
1163 | | - "Front", "Surround", "CLFE", "Side" |
---|
| 1156 | +static const char * const channel_name[] = { |
---|
| 1157 | + "Front", "Surround", "CLFE", "Side", "Back", |
---|
1164 | 1158 | }; |
---|
1165 | 1159 | |
---|
1166 | 1160 | /* give some appropriate ctl name prefix for the given line out channel */ |
---|
.. | .. |
---|
1186 | 1180 | |
---|
1187 | 1181 | /* multi-io channels */ |
---|
1188 | 1182 | if (ch >= cfg->line_outs) |
---|
1189 | | - return channel_name[ch]; |
---|
| 1183 | + goto fixed_name; |
---|
1190 | 1184 | |
---|
1191 | 1185 | switch (cfg->line_out_type) { |
---|
1192 | 1186 | case AUTO_PIN_SPEAKER_OUT: |
---|
.. | .. |
---|
1238 | 1232 | if (cfg->line_outs == 1 && !spec->multi_ios) |
---|
1239 | 1233 | return "Line Out"; |
---|
1240 | 1234 | |
---|
| 1235 | + fixed_name: |
---|
1241 | 1236 | if (ch >= ARRAY_SIZE(channel_name)) { |
---|
1242 | 1237 | snd_BUG(); |
---|
1243 | 1238 | return "PCM"; |
---|
.. | .. |
---|
3913 | 3908 | return 0; |
---|
3914 | 3909 | } |
---|
3915 | 3910 | |
---|
| 3911 | +#ifdef CONFIG_SND_HDA_GENERIC_LEDS |
---|
| 3912 | +/* |
---|
| 3913 | + * vmaster mute LED hook helpers |
---|
| 3914 | + */ |
---|
| 3915 | + |
---|
| 3916 | +static int create_mute_led_cdev(struct hda_codec *codec, |
---|
| 3917 | + int (*callback)(struct led_classdev *, |
---|
| 3918 | + enum led_brightness), |
---|
| 3919 | + bool micmute) |
---|
| 3920 | +{ |
---|
| 3921 | + struct hda_gen_spec *spec = codec->spec; |
---|
| 3922 | + struct led_classdev *cdev; |
---|
| 3923 | + int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE; |
---|
| 3924 | + int err; |
---|
| 3925 | + |
---|
| 3926 | + cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL); |
---|
| 3927 | + if (!cdev) |
---|
| 3928 | + return -ENOMEM; |
---|
| 3929 | + |
---|
| 3930 | + cdev->name = micmute ? "hda::micmute" : "hda::mute"; |
---|
| 3931 | + cdev->max_brightness = 1; |
---|
| 3932 | + cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute"; |
---|
| 3933 | + cdev->brightness_set_blocking = callback; |
---|
| 3934 | + cdev->brightness = ledtrig_audio_get(idx); |
---|
| 3935 | + cdev->flags = LED_CORE_SUSPENDRESUME; |
---|
| 3936 | + |
---|
| 3937 | + err = led_classdev_register(&codec->core.dev, cdev); |
---|
| 3938 | + if (err < 0) |
---|
| 3939 | + return err; |
---|
| 3940 | + spec->led_cdevs[idx] = cdev; |
---|
| 3941 | + return 0; |
---|
| 3942 | +} |
---|
| 3943 | + |
---|
| 3944 | +static void vmaster_update_mute_led(void *private_data, int enabled) |
---|
| 3945 | +{ |
---|
| 3946 | + ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON); |
---|
| 3947 | +} |
---|
| 3948 | + |
---|
| 3949 | +/** |
---|
| 3950 | + * snd_dha_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED |
---|
| 3951 | + * @codec: the HDA codec |
---|
| 3952 | + * @callback: the callback for LED classdev brightness_set_blocking |
---|
| 3953 | + */ |
---|
| 3954 | +int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, |
---|
| 3955 | + int (*callback)(struct led_classdev *, |
---|
| 3956 | + enum led_brightness)) |
---|
| 3957 | +{ |
---|
| 3958 | + struct hda_gen_spec *spec = codec->spec; |
---|
| 3959 | + int err; |
---|
| 3960 | + |
---|
| 3961 | + if (callback) { |
---|
| 3962 | + err = create_mute_led_cdev(codec, callback, false); |
---|
| 3963 | + if (err) { |
---|
| 3964 | + codec_warn(codec, "failed to create a mute LED cdev\n"); |
---|
| 3965 | + return err; |
---|
| 3966 | + } |
---|
| 3967 | + } |
---|
| 3968 | + |
---|
| 3969 | + if (spec->vmaster_mute.hook) |
---|
| 3970 | + codec_err(codec, "vmaster hook already present before cdev!\n"); |
---|
| 3971 | + |
---|
| 3972 | + spec->vmaster_mute.hook = vmaster_update_mute_led; |
---|
| 3973 | + spec->vmaster_mute_enum = 1; |
---|
| 3974 | + return 0; |
---|
| 3975 | +} |
---|
| 3976 | +EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev); |
---|
| 3977 | + |
---|
3916 | 3978 | /* |
---|
3917 | 3979 | * mic mute LED hook helpers |
---|
3918 | 3980 | */ |
---|
.. | .. |
---|
3947 | 4009 | if (val == spec->micmute_led.led_value) |
---|
3948 | 4010 | return; |
---|
3949 | 4011 | spec->micmute_led.led_value = val; |
---|
3950 | | - if (spec->micmute_led.update) |
---|
3951 | | - spec->micmute_led.update(codec); |
---|
| 4012 | + ledtrig_audio_set(LED_AUDIO_MICMUTE, |
---|
| 4013 | + spec->micmute_led.led_value ? LED_ON : LED_OFF); |
---|
3952 | 4014 | } |
---|
3953 | 4015 | |
---|
3954 | 4016 | static void update_micmute_led(struct hda_codec *codec, |
---|
.. | .. |
---|
4020 | 4082 | .put = micmute_led_mode_put, |
---|
4021 | 4083 | }; |
---|
4022 | 4084 | |
---|
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 *)) |
---|
| 4085 | +/* Set up the capture sync hook for controlling the mic-mute LED */ |
---|
| 4086 | +static int add_micmute_led_hook(struct hda_codec *codec) |
---|
4037 | 4087 | { |
---|
4038 | 4088 | struct hda_gen_spec *spec = codec->spec; |
---|
4039 | 4089 | |
---|
.. | .. |
---|
4041 | 4091 | spec->micmute_led.capture = 0; |
---|
4042 | 4092 | spec->micmute_led.led_value = -1; |
---|
4043 | 4093 | spec->micmute_led.old_hook = spec->cap_sync_hook; |
---|
4044 | | - spec->micmute_led.update = hook; |
---|
4045 | 4094 | spec->cap_sync_hook = update_micmute_led; |
---|
4046 | 4095 | if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl)) |
---|
4047 | 4096 | return -ENOMEM; |
---|
4048 | 4097 | return 0; |
---|
4049 | 4098 | } |
---|
4050 | | -EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led); |
---|
| 4099 | + |
---|
| 4100 | +/** |
---|
| 4101 | + * snd_dha_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED |
---|
| 4102 | + * @codec: the HDA codec |
---|
| 4103 | + * @callback: the callback for LED classdev brightness_set_blocking |
---|
| 4104 | + * |
---|
| 4105 | + * Called from the codec drivers for offering the mic mute LED controls. |
---|
| 4106 | + * This creates a LED classdev and sets up the cap_sync_hook that is called at |
---|
| 4107 | + * each time when the capture mixer switch changes. |
---|
| 4108 | + * |
---|
| 4109 | + * When NULL is passed to @callback, no classdev is created but only the |
---|
| 4110 | + * LED-trigger is set up. |
---|
| 4111 | + * |
---|
| 4112 | + * Returns 0 or a negative error. |
---|
| 4113 | + */ |
---|
| 4114 | +int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, |
---|
| 4115 | + int (*callback)(struct led_classdev *, |
---|
| 4116 | + enum led_brightness)) |
---|
| 4117 | +{ |
---|
| 4118 | + int err; |
---|
| 4119 | + |
---|
| 4120 | + if (callback) { |
---|
| 4121 | + err = create_mute_led_cdev(codec, callback, true); |
---|
| 4122 | + if (err) { |
---|
| 4123 | + codec_warn(codec, "failed to create a mic-mute LED cdev\n"); |
---|
| 4124 | + return err; |
---|
| 4125 | + } |
---|
| 4126 | + } |
---|
| 4127 | + |
---|
| 4128 | + return add_micmute_led_hook(codec); |
---|
| 4129 | +} |
---|
| 4130 | +EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev); |
---|
| 4131 | +#endif /* CONFIG_SND_HDA_GENERIC_LEDS */ |
---|
4051 | 4132 | |
---|
4052 | 4133 | /* |
---|
4053 | 4134 | * parse digital I/Os and set up NIDs in BIOS auto-parse mode |
---|
.. | .. |
---|
4059 | 4140 | int i, nums; |
---|
4060 | 4141 | hda_nid_t dig_nid, pin; |
---|
4061 | 4142 | |
---|
4062 | | - /* support multiple SPDIFs; the secondary is set up as a slave */ |
---|
| 4143 | + /* support multiple SPDIFs; the secondary is set up as a follower */ |
---|
4063 | 4144 | nums = 0; |
---|
4064 | 4145 | for (i = 0; i < spec->autocfg.dig_outs; i++) { |
---|
4065 | 4146 | pin = spec->autocfg.dig_out_pins[i]; |
---|
.. | .. |
---|
4078 | 4159 | spec->multiout.dig_out_nid = dig_nid; |
---|
4079 | 4160 | spec->dig_out_type = spec->autocfg.dig_out_type[0]; |
---|
4080 | 4161 | } else { |
---|
4081 | | - spec->multiout.slave_dig_outs = spec->slave_dig_outs; |
---|
4082 | | - if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) |
---|
| 4162 | + spec->multiout.follower_dig_outs = spec->follower_dig_outs; |
---|
| 4163 | + if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1) |
---|
4083 | 4164 | break; |
---|
4084 | | - spec->slave_dig_outs[nums - 1] = dig_nid; |
---|
| 4165 | + spec->follower_dig_outs[nums - 1] = dig_nid; |
---|
4085 | 4166 | } |
---|
4086 | 4167 | nums++; |
---|
4087 | 4168 | } |
---|
.. | .. |
---|
4397 | 4478 | */ |
---|
4398 | 4479 | |
---|
4399 | 4480 | /* 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) |
---|
| 4481 | +static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins) |
---|
4401 | 4482 | { |
---|
4402 | 4483 | int i; |
---|
4403 | 4484 | bool present = false; |
---|
.. | .. |
---|
4416 | 4497 | } |
---|
4417 | 4498 | |
---|
4418 | 4499 | /* standard HP/line-out auto-mute helper */ |
---|
4419 | | -static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, |
---|
| 4500 | +static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins, |
---|
4420 | 4501 | int *paths, bool mute) |
---|
4421 | 4502 | { |
---|
4422 | 4503 | struct hda_gen_spec *spec = codec->spec; |
---|
.. | .. |
---|
4536 | 4617 | else |
---|
4537 | 4618 | snd_hda_gen_update_outputs(codec); |
---|
4538 | 4619 | |
---|
4539 | | - /* sync the whole vmaster slaves to reflect the new auto-mute status */ |
---|
| 4620 | + /* sync the whole vmaster followers to reflect the new auto-mute status */ |
---|
4540 | 4621 | if (spec->auto_mute_via_amp && !codec->bus->shutdown) |
---|
4541 | 4622 | snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); |
---|
4542 | 4623 | } |
---|
.. | .. |
---|
5180 | 5261 | * Build control elements |
---|
5181 | 5262 | */ |
---|
5182 | 5263 | |
---|
5183 | | -/* slave controls for virtual master */ |
---|
5184 | | -static const char * const slave_pfxs[] = { |
---|
| 5264 | +/* follower controls for virtual master */ |
---|
| 5265 | +static const char * const follower_pfxs[] = { |
---|
5185 | 5266 | "Front", "Surround", "Center", "LFE", "Side", |
---|
5186 | 5267 | "Headphone", "Speaker", "Mono", "Line Out", |
---|
5187 | 5268 | "CLFE", "Bass Speaker", "PCM", |
---|
.. | .. |
---|
5233 | 5314 | if (!spec->no_analog && !spec->suppress_vmaster && |
---|
5234 | 5315 | !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { |
---|
5235 | 5316 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", |
---|
5236 | | - spec->vmaster_tlv, slave_pfxs, |
---|
| 5317 | + spec->vmaster_tlv, follower_pfxs, |
---|
5237 | 5318 | "Playback Volume"); |
---|
5238 | 5319 | if (err < 0) |
---|
5239 | 5320 | return err; |
---|
.. | .. |
---|
5241 | 5322 | if (!spec->no_analog && !spec->suppress_vmaster && |
---|
5242 | 5323 | !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { |
---|
5243 | 5324 | err = __snd_hda_add_vmaster(codec, "Master Playback Switch", |
---|
5244 | | - NULL, slave_pfxs, |
---|
| 5325 | + NULL, follower_pfxs, |
---|
5245 | 5326 | "Playback Switch", |
---|
5246 | 5327 | true, &spec->vmaster_mute.sw_kctl); |
---|
5247 | 5328 | if (err < 0) |
---|
.. | .. |
---|
5756 | 5837 | spec->stream_name_digital); |
---|
5757 | 5838 | if (!info) |
---|
5758 | 5839 | return -ENOMEM; |
---|
5759 | | - codec->slave_dig_outs = spec->multiout.slave_dig_outs; |
---|
| 5840 | + codec->follower_dig_outs = spec->multiout.follower_dig_outs; |
---|
5760 | 5841 | spec->pcm_rec[1] = info; |
---|
5761 | 5842 | if (spec->dig_out_type) |
---|
5762 | 5843 | info->pcm_type = spec->dig_out_type; |
---|
.. | .. |
---|
6023 | 6104 | /* call init functions of standard auto-mute helpers */ |
---|
6024 | 6105 | update_automute_all(codec); |
---|
6025 | 6106 | |
---|
6026 | | - regcache_sync(codec->core.regmap); |
---|
| 6107 | + snd_hda_regmap_sync(codec); |
---|
6027 | 6108 | |
---|
6028 | 6109 | if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) |
---|
6029 | 6110 | snd_hda_sync_vmaster_hook(&spec->vmaster_mute); |
---|