root/sound/hda/hdac_component.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hdac_acomp_release
  2. hdac_get_acomp
  3. snd_hdac_set_codec_wakeup
  4. snd_hdac_display_power
  5. snd_hdac_sync_audio_rate
  6. snd_hdac_acomp_get_eld
  7. hdac_component_master_bind
  8. hdac_component_master_unbind
  9. snd_hdac_acomp_register_notifier
  10. snd_hdac_acomp_init
  11. snd_hdac_acomp_exit

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

/* [<][>][^][v][top][bottom][index][help] */