LCOV - code coverage report
Current view: top level - sound/hda - hdac_component.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 121 0.0 %
Date: 2022-04-01 14:17:54 Functions: 0 10 0.0 %
Branches: 0 108 0.0 %

           Branch data     Line data    Source code
       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                 :          0 : static void hdac_acomp_release(struct device *dev, void *res)
      14                 :            : {
      15                 :          0 : }
      16                 :            : 
      17                 :          0 : static struct drm_audio_component *hdac_get_acomp(struct device *dev)
      18                 :            : {
      19                 :          0 :         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                 :          0 : int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
      36                 :            : {
      37                 :          0 :         struct drm_audio_component *acomp = bus->audio_component;
      38                 :            : 
      39   [ #  #  #  #  :          0 :         if (!acomp || !acomp->ops)
             #  #  #  # ]
      40                 :            :                 return -ENODEV;
      41                 :            : 
      42   [ #  #  #  #  :          0 :         if (!acomp->ops->codec_wake_override)
                   #  # ]
      43                 :            :                 return 0;
      44                 :            : 
      45                 :          0 :         dev_dbg(bus->dev, "%s codec wakeup\n",
      46                 :            :                 enable ? "enable" : "disable");
      47                 :            : 
      48                 :          0 :         acomp->ops->codec_wake_override(acomp->dev, enable);
      49                 :            : 
      50                 :          0 :         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                 :          0 : void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
      67                 :            : {
      68                 :          0 :         struct drm_audio_component *acomp = bus->audio_component;
      69                 :            : 
      70                 :          0 :         dev_dbg(bus->dev, "display power %s\n",
      71                 :            :                 enable ? "enable" : "disable");
      72                 :            : 
      73                 :          0 :         mutex_lock(&bus->lock);
      74         [ #  # ]:          0 :         if (enable)
      75                 :          0 :                 set_bit(idx, &bus->display_power_status);
      76                 :            :         else
      77                 :          0 :                 clear_bit(idx, &bus->display_power_status);
      78                 :            : 
      79   [ #  #  #  # ]:          0 :         if (!acomp || !acomp->ops)
      80                 :          0 :                 goto unlock;
      81                 :            : 
      82         [ #  # ]:          0 :         if (bus->display_power_status) {
      83         [ #  # ]:          0 :                 if (!bus->display_power_active) {
      84                 :          0 :                         unsigned long cookie = -1;
      85                 :            : 
      86         [ #  # ]:          0 :                         if (acomp->ops->get_power)
      87                 :          0 :                                 cookie = acomp->ops->get_power(acomp->dev);
      88                 :            : 
      89         [ #  # ]:          0 :                         snd_hdac_set_codec_wakeup(bus, true);
      90         [ #  # ]:          0 :                         snd_hdac_set_codec_wakeup(bus, false);
      91                 :          0 :                         bus->display_power_active = cookie;
      92                 :            :                 }
      93                 :            :         } else {
      94         [ #  # ]:          0 :                 if (bus->display_power_active) {
      95                 :          0 :                         unsigned long cookie = bus->display_power_active;
      96                 :            : 
      97         [ #  # ]:          0 :                         if (acomp->ops->put_power)
      98                 :          0 :                                 acomp->ops->put_power(acomp->dev, cookie);
      99                 :            : 
     100                 :          0 :                         bus->display_power_active = 0;
     101                 :            :                 }
     102                 :            :         }
     103                 :          0 :  unlock:
     104                 :          0 :         mutex_unlock(&bus->lock);
     105                 :          0 : }
     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                 :          0 : int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
     122                 :            :                              int dev_id, int rate)
     123                 :            : {
     124                 :          0 :         struct hdac_bus *bus = codec->bus;
     125                 :          0 :         struct drm_audio_component *acomp = bus->audio_component;
     126                 :          0 :         int port, pipe;
     127                 :            : 
     128   [ #  #  #  #  :          0 :         if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
                   #  # ]
     129                 :            :                 return -ENODEV;
     130                 :          0 :         port = nid;
     131   [ #  #  #  # ]:          0 :         if (acomp->audio_ops && acomp->audio_ops->pin2port) {
     132                 :          0 :                 port = acomp->audio_ops->pin2port(codec, nid);
     133         [ #  # ]:          0 :                 if (port < 0)
     134                 :            :                         return -EINVAL;
     135                 :            :         }
     136                 :          0 :         pipe = dev_id;
     137                 :          0 :         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                 :          0 : 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                 :          0 :         struct hdac_bus *bus = codec->bus;
     166                 :          0 :         struct drm_audio_component *acomp = bus->audio_component;
     167                 :          0 :         int port, pipe;
     168                 :            : 
     169   [ #  #  #  #  :          0 :         if (!acomp || !acomp->ops || !acomp->ops->get_eld)
                   #  # ]
     170                 :            :                 return -ENODEV;
     171                 :            : 
     172                 :          0 :         port = nid;
     173   [ #  #  #  # ]:          0 :         if (acomp->audio_ops && acomp->audio_ops->pin2port) {
     174                 :          0 :                 port = acomp->audio_ops->pin2port(codec, nid);
     175         [ #  # ]:          0 :                 if (port < 0)
     176                 :            :                         return -EINVAL;
     177                 :            :         }
     178                 :          0 :         pipe = dev_id;
     179                 :          0 :         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                 :          0 : static int hdac_component_master_bind(struct device *dev)
     185                 :            : {
     186                 :          0 :         struct drm_audio_component *acomp = hdac_get_acomp(dev);
     187                 :          0 :         int ret;
     188                 :            : 
     189   [ #  #  #  # ]:          0 :         if (WARN_ON(!acomp))
     190                 :            :                 return -EINVAL;
     191                 :            : 
     192                 :          0 :         ret = component_bind_all(dev, acomp);
     193         [ #  # ]:          0 :         if (ret < 0)
     194                 :            :                 return ret;
     195                 :            : 
     196   [ #  #  #  #  :          0 :         if (WARN_ON(!(acomp->dev && acomp->ops))) {
             #  #  #  # ]
     197                 :          0 :                 ret = -EINVAL;
     198                 :          0 :                 goto out_unbind;
     199                 :            :         }
     200                 :            : 
     201                 :            :         /* pin the module to avoid dynamic unbinding, but only if given */
     202         [ #  # ]:          0 :         if (!try_module_get(acomp->ops->owner)) {
     203                 :          0 :                 ret = -ENODEV;
     204                 :          0 :                 goto out_unbind;
     205                 :            :         }
     206                 :            : 
     207   [ #  #  #  # ]:          0 :         if (acomp->audio_ops && acomp->audio_ops->master_bind) {
     208                 :          0 :                 ret = acomp->audio_ops->master_bind(dev, acomp);
     209         [ #  # ]:          0 :                 if (ret < 0)
     210                 :          0 :                         goto module_put;
     211                 :            :         }
     212                 :            : 
     213                 :            :         return 0;
     214                 :            : 
     215                 :            :  module_put:
     216                 :          0 :         module_put(acomp->ops->owner);
     217                 :          0 : out_unbind:
     218                 :          0 :         component_unbind_all(dev, acomp);
     219                 :            : 
     220                 :          0 :         return ret;
     221                 :            : }
     222                 :            : 
     223                 :          0 : static void hdac_component_master_unbind(struct device *dev)
     224                 :            : {
     225                 :          0 :         struct drm_audio_component *acomp = hdac_get_acomp(dev);
     226                 :            : 
     227   [ #  #  #  # ]:          0 :         if (acomp->audio_ops && acomp->audio_ops->master_unbind)
     228                 :          0 :                 acomp->audio_ops->master_unbind(dev, acomp);
     229                 :          0 :         module_put(acomp->ops->owner);
     230                 :          0 :         component_unbind_all(dev, acomp);
     231   [ #  #  #  #  :          0 :         WARN_ON(acomp->ops || acomp->dev);
                   #  # ]
     232                 :          0 : }
     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                 :          0 : int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
     252                 :            :                                     const struct drm_audio_component_audio_ops *aops)
     253                 :            : {
     254         [ #  # ]:          0 :         if (!bus->audio_component)
     255                 :            :                 return -ENODEV;
     256                 :            : 
     257                 :          0 :         bus->audio_component->audio_ops = aops;
     258                 :          0 :         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                 :            :  * @aops: audio component ops
     266                 :            :  * @match_master: match function for finding components
     267                 :            :  * @extra_size: Extra bytes to allocate
     268                 :            :  *
     269                 :            :  * This function is supposed to be used only by a HD-audio controller
     270                 :            :  * driver that needs the interaction with graphics driver.
     271                 :            :  *
     272                 :            :  * This function initializes and sets up the audio component to communicate
     273                 :            :  * with graphics driver.
     274                 :            :  *
     275                 :            :  * Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
     276                 :            :  * binding with the DRM component.  Each caller needs to sync via master_bind
     277                 :            :  * audio_ops.
     278                 :            :  *
     279                 :            :  * Returns zero for success or a negative error code.
     280                 :            :  */
     281                 :          0 : int snd_hdac_acomp_init(struct hdac_bus *bus,
     282                 :            :                         const struct drm_audio_component_audio_ops *aops,
     283                 :            :                         int (*match_master)(struct device *, int, void *),
     284                 :            :                         size_t extra_size)
     285                 :            : {
     286                 :          0 :         struct component_match *match = NULL;
     287                 :          0 :         struct device *dev = bus->dev;
     288                 :          0 :         struct drm_audio_component *acomp;
     289                 :          0 :         int ret;
     290                 :            : 
     291   [ #  #  #  # ]:          0 :         if (WARN_ON(hdac_get_acomp(dev)))
     292                 :            :                 return -EBUSY;
     293                 :            : 
     294                 :          0 :         acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
     295                 :            :                              GFP_KERNEL);
     296         [ #  # ]:          0 :         if (!acomp)
     297                 :            :                 return -ENOMEM;
     298                 :          0 :         acomp->audio_ops = aops;
     299                 :          0 :         bus->audio_component = acomp;
     300                 :          0 :         devres_add(dev, acomp);
     301                 :            : 
     302                 :          0 :         component_match_add_typed(dev, &match, match_master, bus);
     303                 :          0 :         ret = component_master_add_with_match(dev, &hdac_component_master_ops,
     304                 :            :                                               match);
     305         [ #  # ]:          0 :         if (ret < 0)
     306                 :          0 :                 goto out_err;
     307                 :            : 
     308                 :            :         return 0;
     309                 :            : 
     310                 :            : out_err:
     311                 :          0 :         bus->audio_component = NULL;
     312                 :          0 :         devres_destroy(dev, hdac_acomp_release, NULL, NULL);
     313                 :          0 :         dev_info(dev, "failed to add audio component master (%d)\n", ret);
     314                 :            : 
     315                 :          0 :         return ret;
     316                 :            : }
     317                 :            : EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
     318                 :            : 
     319                 :            : /**
     320                 :            :  * snd_hdac_acomp_exit - Finalize audio component
     321                 :            :  * @bus: HDA core bus
     322                 :            :  *
     323                 :            :  * This function is supposed to be used only by a HD-audio controller
     324                 :            :  * driver that needs the interaction with graphics driver.
     325                 :            :  *
     326                 :            :  * This function releases the audio component that has been used.
     327                 :            :  *
     328                 :            :  * Returns zero for success or a negative error code.
     329                 :            :  */
     330                 :          0 : int snd_hdac_acomp_exit(struct hdac_bus *bus)
     331                 :            : {
     332                 :          0 :         struct device *dev = bus->dev;
     333                 :          0 :         struct drm_audio_component *acomp = bus->audio_component;
     334                 :            : 
     335         [ #  # ]:          0 :         if (!acomp)
     336                 :            :                 return 0;
     337                 :            : 
     338   [ #  #  #  #  :          0 :         if (WARN_ON(bus->display_power_active) && acomp->ops)
                   #  # ]
     339                 :          0 :                 acomp->ops->put_power(acomp->dev, bus->display_power_active);
     340                 :            : 
     341                 :          0 :         bus->display_power_active = 0;
     342                 :          0 :         bus->display_power_status = 0;
     343                 :            : 
     344                 :          0 :         component_master_del(dev, &hdac_component_master_ops);
     345                 :            : 
     346                 :          0 :         bus->audio_component = NULL;
     347                 :          0 :         devres_destroy(dev, hdac_acomp_release, NULL, NULL);
     348                 :            : 
     349                 :          0 :         return 0;
     350                 :            : }
     351                 :            : EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);

Generated by: LCOV version 1.14