1a57942bfSTakashi Iwai // SPDX-License-Identifier: GPL-2.0 2a57942bfSTakashi Iwai // hdac_component.c - routines for sync between HD-A core and DRM driver 3a57942bfSTakashi Iwai 4a57942bfSTakashi Iwai #include <linux/init.h> 5a57942bfSTakashi Iwai #include <linux/module.h> 6a57942bfSTakashi Iwai #include <linux/pci.h> 7a57942bfSTakashi Iwai #include <linux/component.h> 8a57942bfSTakashi Iwai #include <sound/core.h> 9a57942bfSTakashi Iwai #include <sound/hdaudio.h> 10a57942bfSTakashi Iwai #include <sound/hda_component.h> 11a57942bfSTakashi Iwai #include <sound/hda_register.h> 12a57942bfSTakashi Iwai 13a57942bfSTakashi Iwai static void hdac_acomp_release(struct device *dev, void *res) 14a57942bfSTakashi Iwai { 15a57942bfSTakashi Iwai } 16a57942bfSTakashi Iwai 17a57942bfSTakashi Iwai static struct drm_audio_component *hdac_get_acomp(struct device *dev) 18a57942bfSTakashi Iwai { 19a57942bfSTakashi Iwai return devres_find(dev, hdac_acomp_release, NULL, NULL); 20a57942bfSTakashi Iwai } 21a57942bfSTakashi Iwai 22a57942bfSTakashi Iwai /** 23a57942bfSTakashi Iwai * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup 24a57942bfSTakashi Iwai * @bus: HDA core bus 25a57942bfSTakashi Iwai * @enable: enable or disable the wakeup 26a57942bfSTakashi Iwai * 27a57942bfSTakashi Iwai * This function is supposed to be used only by a HD-audio controller 28a57942bfSTakashi Iwai * driver that needs the interaction with graphics driver. 29a57942bfSTakashi Iwai * 30a57942bfSTakashi Iwai * This function should be called during the chip reset, also called at 31a57942bfSTakashi Iwai * resume for updating STATESTS register read. 32a57942bfSTakashi Iwai * 33a57942bfSTakashi Iwai * Returns zero for success or a negative error code. 34a57942bfSTakashi Iwai */ 35a57942bfSTakashi Iwai int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) 36a57942bfSTakashi Iwai { 37a57942bfSTakashi Iwai struct drm_audio_component *acomp = bus->audio_component; 38a57942bfSTakashi Iwai 39a57942bfSTakashi Iwai if (!acomp || !acomp->ops) 40a57942bfSTakashi Iwai return -ENODEV; 41a57942bfSTakashi Iwai 42a57942bfSTakashi Iwai if (!acomp->ops->codec_wake_override) 43a57942bfSTakashi Iwai return 0; 44a57942bfSTakashi Iwai 45a57942bfSTakashi Iwai dev_dbg(bus->dev, "%s codec wakeup\n", 46a57942bfSTakashi Iwai enable ? "enable" : "disable"); 47a57942bfSTakashi Iwai 48a57942bfSTakashi Iwai acomp->ops->codec_wake_override(acomp->dev, enable); 49a57942bfSTakashi Iwai 50a57942bfSTakashi Iwai return 0; 51a57942bfSTakashi Iwai } 52a57942bfSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); 53a57942bfSTakashi Iwai 54a57942bfSTakashi Iwai /** 55a57942bfSTakashi Iwai * snd_hdac_display_power - Power up / down the power refcount 56a57942bfSTakashi Iwai * @bus: HDA core bus 57029d92c2STakashi Iwai * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller 58a57942bfSTakashi Iwai * @enable: power up or down 59a57942bfSTakashi Iwai * 60029d92c2STakashi Iwai * This function is used by either HD-audio controller or codec driver that 61029d92c2STakashi Iwai * needs the interaction with graphics driver. 62a57942bfSTakashi Iwai * 63029d92c2STakashi Iwai * This function updates the power status, and calls the get_power() and 64a57942bfSTakashi Iwai * put_power() ops accordingly, toggling the codec wakeup, too. 65a57942bfSTakashi Iwai */ 664f799e73STakashi Iwai void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) 67a57942bfSTakashi Iwai { 68a57942bfSTakashi Iwai struct drm_audio_component *acomp = bus->audio_component; 69a57942bfSTakashi Iwai 70a57942bfSTakashi Iwai dev_dbg(bus->dev, "display power %s\n", 71a57942bfSTakashi Iwai enable ? "enable" : "disable"); 72d7a181daSTakashi Iwai 73d7a181daSTakashi Iwai mutex_lock(&bus->lock); 74029d92c2STakashi Iwai if (enable) 75029d92c2STakashi Iwai set_bit(idx, &bus->display_power_status); 76029d92c2STakashi Iwai else 77029d92c2STakashi Iwai clear_bit(idx, &bus->display_power_status); 78a57942bfSTakashi Iwai 79029d92c2STakashi Iwai if (!acomp || !acomp->ops) 80d7a181daSTakashi Iwai goto unlock; 81029d92c2STakashi Iwai 82029d92c2STakashi Iwai if (bus->display_power_status) { 83029d92c2STakashi Iwai if (!bus->display_power_active) { 84d31c85fcSChris Wilson unsigned long cookie = -1; 85d31c85fcSChris Wilson 86a57942bfSTakashi Iwai if (acomp->ops->get_power) 87d31c85fcSChris Wilson cookie = acomp->ops->get_power(acomp->dev); 88d31c85fcSChris Wilson 89a57942bfSTakashi Iwai snd_hdac_set_codec_wakeup(bus, true); 90a57942bfSTakashi Iwai snd_hdac_set_codec_wakeup(bus, false); 91d31c85fcSChris Wilson bus->display_power_active = cookie; 92a57942bfSTakashi Iwai } 93a57942bfSTakashi Iwai } else { 94029d92c2STakashi Iwai if (bus->display_power_active) { 95d31c85fcSChris Wilson unsigned long cookie = bus->display_power_active; 96d31c85fcSChris Wilson 97a57942bfSTakashi Iwai if (acomp->ops->put_power) 98d31c85fcSChris Wilson acomp->ops->put_power(acomp->dev, cookie); 99d31c85fcSChris Wilson 100d31c85fcSChris Wilson bus->display_power_active = 0; 101029d92c2STakashi Iwai } 102a57942bfSTakashi Iwai } 103d7a181daSTakashi Iwai unlock: 104d7a181daSTakashi Iwai mutex_unlock(&bus->lock); 105a57942bfSTakashi Iwai } 106a57942bfSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_display_power); 107a57942bfSTakashi Iwai 108a57942bfSTakashi Iwai /** 109a57942bfSTakashi Iwai * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate 110a57942bfSTakashi Iwai * @codec: HDA codec 111a57942bfSTakashi Iwai * @nid: the pin widget NID 112a57942bfSTakashi Iwai * @dev_id: device identifier 113a57942bfSTakashi Iwai * @rate: the sample rate to set 114a57942bfSTakashi Iwai * 115a57942bfSTakashi Iwai * This function is supposed to be used only by a HD-audio controller 116a57942bfSTakashi Iwai * driver that needs the interaction with graphics driver. 117a57942bfSTakashi Iwai * 118a57942bfSTakashi Iwai * This function sets N/CTS value based on the given sample rate. 119a57942bfSTakashi Iwai * Returns zero for success, or a negative error code. 120a57942bfSTakashi Iwai */ 121a57942bfSTakashi Iwai int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, 122a57942bfSTakashi Iwai int dev_id, int rate) 123a57942bfSTakashi Iwai { 124a57942bfSTakashi Iwai struct hdac_bus *bus = codec->bus; 125a57942bfSTakashi Iwai struct drm_audio_component *acomp = bus->audio_component; 126a57942bfSTakashi Iwai int port, pipe; 127a57942bfSTakashi Iwai 128a57942bfSTakashi Iwai if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate) 129a57942bfSTakashi Iwai return -ENODEV; 130a57942bfSTakashi Iwai port = nid; 131a57942bfSTakashi Iwai if (acomp->audio_ops && acomp->audio_ops->pin2port) { 132a57942bfSTakashi Iwai port = acomp->audio_ops->pin2port(codec, nid); 133a57942bfSTakashi Iwai if (port < 0) 134a57942bfSTakashi Iwai return -EINVAL; 135a57942bfSTakashi Iwai } 136a57942bfSTakashi Iwai pipe = dev_id; 137a57942bfSTakashi Iwai return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate); 138a57942bfSTakashi Iwai } 139a57942bfSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate); 140a57942bfSTakashi Iwai 141a57942bfSTakashi Iwai /** 142a57942bfSTakashi Iwai * snd_hdac_acomp_get_eld - Get the audio state and ELD via component 143a57942bfSTakashi Iwai * @codec: HDA codec 144a57942bfSTakashi Iwai * @nid: the pin widget NID 145a57942bfSTakashi Iwai * @dev_id: device identifier 146a57942bfSTakashi Iwai * @audio_enabled: the pointer to store the current audio state 147a57942bfSTakashi Iwai * @buffer: the buffer pointer to store ELD bytes 148a57942bfSTakashi Iwai * @max_bytes: the max bytes to be stored on @buffer 149a57942bfSTakashi Iwai * 150a57942bfSTakashi Iwai * This function is supposed to be used only by a HD-audio controller 151a57942bfSTakashi Iwai * driver that needs the interaction with graphics driver. 152a57942bfSTakashi Iwai * 153a57942bfSTakashi Iwai * This function queries the current state of the audio on the given 154a57942bfSTakashi Iwai * digital port and fetches the ELD bytes onto the given buffer. 155a57942bfSTakashi Iwai * It returns the number of bytes for the total ELD data, zero for 156a57942bfSTakashi Iwai * invalid ELD, or a negative error code. 157a57942bfSTakashi Iwai * 158a57942bfSTakashi Iwai * The return size is the total bytes required for the whole ELD bytes, 159a57942bfSTakashi Iwai * thus it may be over @max_bytes. If it's over @max_bytes, it implies 160a57942bfSTakashi Iwai * that only a part of ELD bytes have been fetched. 161a57942bfSTakashi Iwai */ 162a57942bfSTakashi Iwai int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, 163a57942bfSTakashi Iwai bool *audio_enabled, char *buffer, int max_bytes) 164a57942bfSTakashi Iwai { 165a57942bfSTakashi Iwai struct hdac_bus *bus = codec->bus; 166a57942bfSTakashi Iwai struct drm_audio_component *acomp = bus->audio_component; 167a57942bfSTakashi Iwai int port, pipe; 168a57942bfSTakashi Iwai 169a57942bfSTakashi Iwai if (!acomp || !acomp->ops || !acomp->ops->get_eld) 170a57942bfSTakashi Iwai return -ENODEV; 171a57942bfSTakashi Iwai 172a57942bfSTakashi Iwai port = nid; 173a57942bfSTakashi Iwai if (acomp->audio_ops && acomp->audio_ops->pin2port) { 174a57942bfSTakashi Iwai port = acomp->audio_ops->pin2port(codec, nid); 175a57942bfSTakashi Iwai if (port < 0) 176a57942bfSTakashi Iwai return -EINVAL; 177a57942bfSTakashi Iwai } 178a57942bfSTakashi Iwai pipe = dev_id; 179a57942bfSTakashi Iwai return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled, 180a57942bfSTakashi Iwai buffer, max_bytes); 181a57942bfSTakashi Iwai } 182a57942bfSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld); 183a57942bfSTakashi Iwai 184a57942bfSTakashi Iwai static int hdac_component_master_bind(struct device *dev) 185a57942bfSTakashi Iwai { 186a57942bfSTakashi Iwai struct drm_audio_component *acomp = hdac_get_acomp(dev); 187a57942bfSTakashi Iwai int ret; 188a57942bfSTakashi Iwai 189a57942bfSTakashi Iwai if (WARN_ON(!acomp)) 190a57942bfSTakashi Iwai return -EINVAL; 191a57942bfSTakashi Iwai 192a57942bfSTakashi Iwai ret = component_bind_all(dev, acomp); 193a57942bfSTakashi Iwai if (ret < 0) 194a57942bfSTakashi Iwai return ret; 195a57942bfSTakashi Iwai 196a57942bfSTakashi Iwai if (WARN_ON(!(acomp->dev && acomp->ops))) { 197a57942bfSTakashi Iwai ret = -EINVAL; 198a57942bfSTakashi Iwai goto out_unbind; 199a57942bfSTakashi Iwai } 200a57942bfSTakashi Iwai 201a57942bfSTakashi Iwai /* pin the module to avoid dynamic unbinding, but only if given */ 202a57942bfSTakashi Iwai if (!try_module_get(acomp->ops->owner)) { 203a57942bfSTakashi Iwai ret = -ENODEV; 204a57942bfSTakashi Iwai goto out_unbind; 205a57942bfSTakashi Iwai } 206a57942bfSTakashi Iwai 207a57942bfSTakashi Iwai if (acomp->audio_ops && acomp->audio_ops->master_bind) { 208a57942bfSTakashi Iwai ret = acomp->audio_ops->master_bind(dev, acomp); 209a57942bfSTakashi Iwai if (ret < 0) 210a57942bfSTakashi Iwai goto module_put; 211a57942bfSTakashi Iwai } 212a57942bfSTakashi Iwai 213a57942bfSTakashi Iwai return 0; 214a57942bfSTakashi Iwai 215a57942bfSTakashi Iwai module_put: 216a57942bfSTakashi Iwai module_put(acomp->ops->owner); 217a57942bfSTakashi Iwai out_unbind: 218a57942bfSTakashi Iwai component_unbind_all(dev, acomp); 219a57942bfSTakashi Iwai 220a57942bfSTakashi Iwai return ret; 221a57942bfSTakashi Iwai } 222a57942bfSTakashi Iwai 223a57942bfSTakashi Iwai static void hdac_component_master_unbind(struct device *dev) 224a57942bfSTakashi Iwai { 225a57942bfSTakashi Iwai struct drm_audio_component *acomp = hdac_get_acomp(dev); 226a57942bfSTakashi Iwai 227a57942bfSTakashi Iwai if (acomp->audio_ops && acomp->audio_ops->master_unbind) 228a57942bfSTakashi Iwai acomp->audio_ops->master_unbind(dev, acomp); 229a57942bfSTakashi Iwai module_put(acomp->ops->owner); 230a57942bfSTakashi Iwai component_unbind_all(dev, acomp); 231a57942bfSTakashi Iwai WARN_ON(acomp->ops || acomp->dev); 232a57942bfSTakashi Iwai } 233a57942bfSTakashi Iwai 234a57942bfSTakashi Iwai static const struct component_master_ops hdac_component_master_ops = { 235a57942bfSTakashi Iwai .bind = hdac_component_master_bind, 236a57942bfSTakashi Iwai .unbind = hdac_component_master_unbind, 237a57942bfSTakashi Iwai }; 238a57942bfSTakashi Iwai 239a57942bfSTakashi Iwai /** 240a57942bfSTakashi Iwai * snd_hdac_acomp_register_notifier - Register audio component ops 241a57942bfSTakashi Iwai * @bus: HDA core bus 242a57942bfSTakashi Iwai * @aops: audio component ops 243a57942bfSTakashi Iwai * 244a57942bfSTakashi Iwai * This function is supposed to be used only by a HD-audio controller 245a57942bfSTakashi Iwai * driver that needs the interaction with graphics driver. 246a57942bfSTakashi Iwai * 247a57942bfSTakashi Iwai * This function sets the given ops to be called by the graphics driver. 248a57942bfSTakashi Iwai * 249a57942bfSTakashi Iwai * Returns zero for success or a negative error code. 250a57942bfSTakashi Iwai */ 251a57942bfSTakashi Iwai int snd_hdac_acomp_register_notifier(struct hdac_bus *bus, 252a57942bfSTakashi Iwai const struct drm_audio_component_audio_ops *aops) 253a57942bfSTakashi Iwai { 254a57942bfSTakashi Iwai if (!bus->audio_component) 255a57942bfSTakashi Iwai return -ENODEV; 256a57942bfSTakashi Iwai 257a57942bfSTakashi Iwai bus->audio_component->audio_ops = aops; 258a57942bfSTakashi Iwai return 0; 259a57942bfSTakashi Iwai } 260a57942bfSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier); 261a57942bfSTakashi Iwai 262a57942bfSTakashi Iwai /** 263a57942bfSTakashi Iwai * snd_hdac_acomp_init - Initialize audio component 264a57942bfSTakashi Iwai * @bus: HDA core bus 2656e57188fSKeyon Jie * @aops: audio component ops 266a57942bfSTakashi Iwai * @match_master: match function for finding components 267a57942bfSTakashi Iwai * @extra_size: Extra bytes to allocate 268a57942bfSTakashi Iwai * 269a57942bfSTakashi Iwai * This function is supposed to be used only by a HD-audio controller 270a57942bfSTakashi Iwai * driver that needs the interaction with graphics driver. 271a57942bfSTakashi Iwai * 272a57942bfSTakashi Iwai * This function initializes and sets up the audio component to communicate 273a57942bfSTakashi Iwai * with graphics driver. 274a57942bfSTakashi Iwai * 275a57942bfSTakashi Iwai * Unlike snd_hdac_i915_init(), this function doesn't synchronize with the 276a57942bfSTakashi Iwai * binding with the DRM component. Each caller needs to sync via master_bind 277a57942bfSTakashi Iwai * audio_ops. 278a57942bfSTakashi Iwai * 279a57942bfSTakashi Iwai * Returns zero for success or a negative error code. 280a57942bfSTakashi Iwai */ 281a57942bfSTakashi Iwai int snd_hdac_acomp_init(struct hdac_bus *bus, 282a57942bfSTakashi Iwai const struct drm_audio_component_audio_ops *aops, 2838857c7d0SDaniel Vetter int (*match_master)(struct device *, int, void *), 284a57942bfSTakashi Iwai size_t extra_size) 285a57942bfSTakashi Iwai { 286a57942bfSTakashi Iwai struct component_match *match = NULL; 287a57942bfSTakashi Iwai struct device *dev = bus->dev; 288a57942bfSTakashi Iwai struct drm_audio_component *acomp; 289a57942bfSTakashi Iwai int ret; 290a57942bfSTakashi Iwai 291a57942bfSTakashi Iwai if (WARN_ON(hdac_get_acomp(dev))) 292a57942bfSTakashi Iwai return -EBUSY; 293a57942bfSTakashi Iwai 294a57942bfSTakashi Iwai acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size, 295a57942bfSTakashi Iwai GFP_KERNEL); 296a57942bfSTakashi Iwai if (!acomp) 297a57942bfSTakashi Iwai return -ENOMEM; 298a57942bfSTakashi Iwai acomp->audio_ops = aops; 299a57942bfSTakashi Iwai bus->audio_component = acomp; 300a57942bfSTakashi Iwai devres_add(dev, acomp); 301a57942bfSTakashi Iwai 3028857c7d0SDaniel Vetter component_match_add_typed(dev, &match, match_master, bus); 303a57942bfSTakashi Iwai ret = component_master_add_with_match(dev, &hdac_component_master_ops, 304a57942bfSTakashi Iwai match); 305a57942bfSTakashi Iwai if (ret < 0) 306a57942bfSTakashi Iwai goto out_err; 307a57942bfSTakashi Iwai 308a57942bfSTakashi Iwai return 0; 309a57942bfSTakashi Iwai 310a57942bfSTakashi Iwai out_err: 311a57942bfSTakashi Iwai bus->audio_component = NULL; 312a57942bfSTakashi Iwai devres_destroy(dev, hdac_acomp_release, NULL, NULL); 313a57942bfSTakashi Iwai dev_info(dev, "failed to add audio component master (%d)\n", ret); 314a57942bfSTakashi Iwai 315a57942bfSTakashi Iwai return ret; 316a57942bfSTakashi Iwai } 317a57942bfSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_acomp_init); 318a57942bfSTakashi Iwai 319a57942bfSTakashi Iwai /** 320a57942bfSTakashi Iwai * snd_hdac_acomp_exit - Finalize audio component 321a57942bfSTakashi Iwai * @bus: HDA core bus 322a57942bfSTakashi Iwai * 323a57942bfSTakashi Iwai * This function is supposed to be used only by a HD-audio controller 324a57942bfSTakashi Iwai * driver that needs the interaction with graphics driver. 325a57942bfSTakashi Iwai * 326a57942bfSTakashi Iwai * This function releases the audio component that has been used. 327a57942bfSTakashi Iwai * 328a57942bfSTakashi Iwai * Returns zero for success or a negative error code. 329a57942bfSTakashi Iwai */ 330a57942bfSTakashi Iwai int snd_hdac_acomp_exit(struct hdac_bus *bus) 331a57942bfSTakashi Iwai { 332a57942bfSTakashi Iwai struct device *dev = bus->dev; 333a57942bfSTakashi Iwai struct drm_audio_component *acomp = bus->audio_component; 334a57942bfSTakashi Iwai 335a57942bfSTakashi Iwai if (!acomp) 336a57942bfSTakashi Iwai return 0; 337a57942bfSTakashi Iwai 338029d92c2STakashi Iwai if (WARN_ON(bus->display_power_active) && acomp->ops) 339d31c85fcSChris Wilson acomp->ops->put_power(acomp->dev, bus->display_power_active); 340a57942bfSTakashi Iwai 341d31c85fcSChris Wilson bus->display_power_active = 0; 342029d92c2STakashi Iwai bus->display_power_status = 0; 343029d92c2STakashi Iwai 344a57942bfSTakashi Iwai component_master_del(dev, &hdac_component_master_ops); 345a57942bfSTakashi Iwai 346a57942bfSTakashi Iwai bus->audio_component = NULL; 347a57942bfSTakashi Iwai devres_destroy(dev, hdac_acomp_release, NULL, NULL); 348a57942bfSTakashi Iwai 349a57942bfSTakashi Iwai return 0; 350a57942bfSTakashi Iwai } 351a57942bfSTakashi Iwai EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit); 352