.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * HD-audio codec core device |
---|
3 | 4 | */ |
---|
.. | .. |
---|
19 | 20 | |
---|
20 | 21 | static void default_release(struct device *dev) |
---|
21 | 22 | { |
---|
22 | | - snd_hdac_device_exit(container_of(dev, struct hdac_device, dev)); |
---|
| 23 | + snd_hdac_device_exit(dev_to_hdac_dev(dev)); |
---|
23 | 24 | } |
---|
24 | 25 | |
---|
25 | 26 | /** |
---|
.. | .. |
---|
55 | 56 | codec->bus = bus; |
---|
56 | 57 | codec->addr = addr; |
---|
57 | 58 | codec->type = HDA_DEV_CORE; |
---|
| 59 | + mutex_init(&codec->widget_lock); |
---|
| 60 | + mutex_init(&codec->regmap_lock); |
---|
58 | 61 | pm_runtime_set_active(&codec->dev); |
---|
59 | 62 | pm_runtime_get_noresume(&codec->dev); |
---|
60 | 63 | atomic_set(&codec->in_pm, 0); |
---|
.. | .. |
---|
88 | 91 | |
---|
89 | 92 | fg = codec->afg ? codec->afg : codec->mfg; |
---|
90 | 93 | |
---|
91 | | - err = snd_hdac_refresh_widgets(codec, false); |
---|
| 94 | + err = snd_hdac_refresh_widgets(codec); |
---|
92 | 95 | if (err < 0) |
---|
93 | 96 | goto error; |
---|
94 | 97 | |
---|
.. | .. |
---|
134 | 137 | |
---|
135 | 138 | /** |
---|
136 | 139 | * snd_hdac_device_register - register the hd-audio codec base device |
---|
137 | | - * codec: the device to register |
---|
| 140 | + * @codec: the device to register |
---|
138 | 141 | */ |
---|
139 | 142 | int snd_hdac_device_register(struct hdac_device *codec) |
---|
140 | 143 | { |
---|
.. | .. |
---|
143 | 146 | err = device_add(&codec->dev); |
---|
144 | 147 | if (err < 0) |
---|
145 | 148 | return err; |
---|
| 149 | + mutex_lock(&codec->widget_lock); |
---|
146 | 150 | err = hda_widget_sysfs_init(codec); |
---|
| 151 | + mutex_unlock(&codec->widget_lock); |
---|
147 | 152 | if (err < 0) { |
---|
148 | 153 | device_del(&codec->dev); |
---|
149 | 154 | return err; |
---|
.. | .. |
---|
155 | 160 | |
---|
156 | 161 | /** |
---|
157 | 162 | * snd_hdac_device_unregister - unregister the hd-audio codec base device |
---|
158 | | - * codec: the device to unregister |
---|
| 163 | + * @codec: the device to unregister |
---|
159 | 164 | */ |
---|
160 | 165 | void snd_hdac_device_unregister(struct hdac_device *codec) |
---|
161 | 166 | { |
---|
162 | 167 | if (device_is_registered(&codec->dev)) { |
---|
| 168 | + mutex_lock(&codec->widget_lock); |
---|
163 | 169 | hda_widget_sysfs_exit(codec); |
---|
| 170 | + mutex_unlock(&codec->widget_lock); |
---|
164 | 171 | device_del(&codec->dev); |
---|
165 | 172 | snd_hdac_bus_remove_device(codec->bus, codec); |
---|
166 | 173 | } |
---|
.. | .. |
---|
199 | 206 | */ |
---|
200 | 207 | int snd_hdac_codec_modalias(struct hdac_device *codec, char *buf, size_t size) |
---|
201 | 208 | { |
---|
202 | | - return snprintf(buf, size, "hdaudio:v%08Xr%08Xa%02X\n", |
---|
| 209 | + return scnprintf(buf, size, "hdaudio:v%08Xr%08Xa%02X\n", |
---|
203 | 210 | codec->vendor_id, codec->revision_id, codec->type); |
---|
204 | 211 | } |
---|
205 | 212 | EXPORT_SYMBOL_GPL(snd_hdac_codec_modalias); |
---|
.. | .. |
---|
214 | 221 | * |
---|
215 | 222 | * Return an encoded command verb or -1 for error. |
---|
216 | 223 | */ |
---|
217 | | -unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, |
---|
218 | | - unsigned int verb, unsigned int parm) |
---|
| 224 | +static unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, |
---|
| 225 | + unsigned int verb, unsigned int parm) |
---|
219 | 226 | { |
---|
220 | 227 | u32 val, addr; |
---|
221 | 228 | |
---|
.. | .. |
---|
233 | 240 | val |= parm; |
---|
234 | 241 | return val; |
---|
235 | 242 | } |
---|
236 | | -EXPORT_SYMBOL_GPL(snd_hdac_make_cmd); |
---|
237 | 243 | |
---|
238 | 244 | /** |
---|
239 | 245 | * snd_hdac_exec_verb - execute an encoded verb |
---|
.. | .. |
---|
254 | 260 | return codec->exec_verb(codec, cmd, flags, res); |
---|
255 | 261 | return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res); |
---|
256 | 262 | } |
---|
257 | | -EXPORT_SYMBOL_GPL(snd_hdac_exec_verb); |
---|
258 | 263 | |
---|
259 | 264 | |
---|
260 | 265 | /** |
---|
.. | .. |
---|
278 | 283 | |
---|
279 | 284 | /** |
---|
280 | 285 | * _snd_hdac_read_parm - read a parmeter |
---|
| 286 | + * @codec: the codec object |
---|
| 287 | + * @nid: NID to read a parameter |
---|
| 288 | + * @parm: parameter to read |
---|
| 289 | + * @res: pointer to store the read value |
---|
281 | 290 | * |
---|
282 | 291 | * This function returns zero or an error unlike snd_hdac_read_parm(). |
---|
283 | 292 | */ |
---|
.. | .. |
---|
391 | 400 | /** |
---|
392 | 401 | * snd_hdac_refresh_widgets - Reset the widget start/end nodes |
---|
393 | 402 | * @codec: the codec object |
---|
394 | | - * @sysfs: re-initialize sysfs tree, too |
---|
395 | 403 | */ |
---|
396 | | -int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs) |
---|
| 404 | +int snd_hdac_refresh_widgets(struct hdac_device *codec) |
---|
397 | 405 | { |
---|
398 | 406 | hda_nid_t start_nid; |
---|
399 | | - int nums, err; |
---|
| 407 | + int nums, err = 0; |
---|
400 | 408 | |
---|
| 409 | + /* |
---|
| 410 | + * Serialize against multiple threads trying to update the sysfs |
---|
| 411 | + * widgets array. |
---|
| 412 | + */ |
---|
| 413 | + mutex_lock(&codec->widget_lock); |
---|
401 | 414 | nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); |
---|
402 | 415 | if (!start_nid || nums <= 0 || nums >= 0xff) { |
---|
403 | 416 | dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", |
---|
404 | 417 | codec->afg); |
---|
405 | | - return -EINVAL; |
---|
| 418 | + err = -EINVAL; |
---|
| 419 | + goto unlock; |
---|
406 | 420 | } |
---|
407 | 421 | |
---|
408 | | - if (sysfs) { |
---|
409 | | - err = hda_widget_sysfs_reinit(codec, start_nid, nums); |
---|
410 | | - if (err < 0) |
---|
411 | | - return err; |
---|
412 | | - } |
---|
| 422 | + err = hda_widget_sysfs_reinit(codec, start_nid, nums); |
---|
| 423 | + if (err < 0) |
---|
| 424 | + goto unlock; |
---|
413 | 425 | |
---|
414 | 426 | codec->num_nodes = nums; |
---|
415 | 427 | codec->start_nid = start_nid; |
---|
416 | 428 | codec->end_nid = start_nid + nums; |
---|
417 | | - return 0; |
---|
| 429 | +unlock: |
---|
| 430 | + mutex_unlock(&codec->widget_lock); |
---|
| 431 | + return err; |
---|
418 | 432 | } |
---|
419 | 433 | EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); |
---|
420 | 434 | |
---|
.. | .. |
---|
597 | 611 | int snd_hdac_keep_power_up(struct hdac_device *codec) |
---|
598 | 612 | { |
---|
599 | 613 | if (!atomic_inc_not_zero(&codec->in_pm)) { |
---|
600 | | - int ret = pm_runtime_get_if_in_use(&codec->dev); |
---|
| 614 | + int ret = pm_runtime_get_if_active(&codec->dev, true); |
---|
601 | 615 | if (!ret) |
---|
602 | 616 | return -1; |
---|
603 | 617 | if (ret < 0) |
---|
.. | .. |
---|
624 | 638 | EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); |
---|
625 | 639 | #endif |
---|
626 | 640 | |
---|
627 | | -/** |
---|
628 | | - * snd_hdac_link_power - Enable/disable the link power for a codec |
---|
629 | | - * @codec: the codec object |
---|
630 | | - * @bool: enable or disable the link power |
---|
631 | | - */ |
---|
632 | | -int snd_hdac_link_power(struct hdac_device *codec, bool enable) |
---|
633 | | -{ |
---|
634 | | - if (!codec->link_power_control) |
---|
635 | | - return 0; |
---|
636 | | - |
---|
637 | | - if (codec->bus->ops->link_power) |
---|
638 | | - return codec->bus->ops->link_power(codec->bus, enable); |
---|
639 | | - else |
---|
640 | | - return -EINVAL; |
---|
641 | | -} |
---|
642 | | -EXPORT_SYMBOL_GPL(snd_hdac_link_power); |
---|
643 | | - |
---|
644 | 641 | /* codec vendor labels */ |
---|
645 | 642 | struct hda_vendor_id { |
---|
646 | 643 | unsigned int id; |
---|
647 | 644 | const char *name; |
---|
648 | 645 | }; |
---|
649 | 646 | |
---|
650 | | -static struct hda_vendor_id hda_vendor_ids[] = { |
---|
| 647 | +static const struct hda_vendor_id hda_vendor_ids[] = { |
---|
651 | 648 | { 0x1002, "ATI" }, |
---|
652 | 649 | { 0x1013, "Cirrus Logic" }, |
---|
653 | 650 | { 0x1057, "Motorola" }, |
---|
.. | .. |
---|
663 | 660 | { 0x14f1, "Conexant" }, |
---|
664 | 661 | { 0x17e8, "Chrontel" }, |
---|
665 | 662 | { 0x1854, "LG" }, |
---|
| 663 | + { 0x19e5, "Huawei" }, |
---|
666 | 664 | { 0x1aec, "Wolfson Microelectronics" }, |
---|
667 | 665 | { 0x1af4, "QEMU" }, |
---|
668 | 666 | { 0x434d, "C-Media" }, |
---|
.. | .. |
---|
702 | 700 | (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ |
---|
703 | 701 | (((div) - 1) << AC_FMT_DIV_SHIFT)) |
---|
704 | 702 | |
---|
705 | | -static struct hda_rate_tbl rate_bits[] = { |
---|
| 703 | +static const struct hda_rate_tbl rate_bits[] = { |
---|
706 | 704 | /* rate in Hz, ALSA rate bitmask, HDA format value */ |
---|
707 | 705 | |
---|
708 | 706 | /* autodetected value used in snd_hda_query_supported_pcm */ |
---|
.. | .. |
---|
1071 | 1069 | * snd_hdac_sync_power_state - wait until actual power state matches |
---|
1072 | 1070 | * with the target state |
---|
1073 | 1071 | * |
---|
1074 | | - * @hdac: the HDAC device |
---|
| 1072 | + * @codec: the HDAC device |
---|
1075 | 1073 | * @nid: NID to send the command |
---|
1076 | | - * @target_state: target state to check for |
---|
| 1074 | + * @power_state: target power state to wait for |
---|
1077 | 1075 | * |
---|
1078 | 1076 | * Return power state or PS_ERROR if codec rejects GET verb. |
---|
1079 | 1077 | */ |
---|