Commit 7abeb64d authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/drm_audio_component' into for-next

Pull the generic drm_audio_component support, which will be used later
for AMD/ATI and other HD-audio HDMI codec drivers.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents 58cabe87 a57942bf
...@@ -23,6 +23,7 @@ config DRM_I915 ...@@ -23,6 +23,7 @@ config DRM_I915
select SYNC_FILE select SYNC_FILE
select IOSF_MBI select IOSF_MBI
select CRC32 select CRC32
select SND_HDA_I915 if SND_HDA_CORE
help help
Choose this option if you have a system that has "Intel Graphics Choose this option if you have a system that has "Intel Graphics
Media Accelerator" or "HD Graphics" integrated graphics, Media Accelerator" or "HD Graphics" integrated graphics,
......
...@@ -639,11 +639,12 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, ...@@ -639,11 +639,12 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
dev_priv->av_enc_map[pipe] = encoder; dev_priv->av_enc_map[pipe] = encoder;
mutex_unlock(&dev_priv->av_mutex); mutex_unlock(&dev_priv->av_mutex);
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { if (acomp && acomp->base.audio_ops &&
acomp->base.audio_ops->pin_eld_notify) {
/* audio drivers expect pipe = -1 to indicate Non-MST cases */ /* audio drivers expect pipe = -1 to indicate Non-MST cases */
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
pipe = -1; pipe = -1;
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
(int) port, (int) pipe); (int) port, (int) pipe);
} }
...@@ -681,11 +682,12 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, ...@@ -681,11 +682,12 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
dev_priv->av_enc_map[pipe] = NULL; dev_priv->av_enc_map[pipe] = NULL;
mutex_unlock(&dev_priv->av_mutex); mutex_unlock(&dev_priv->av_mutex);
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { if (acomp && acomp->base.audio_ops &&
acomp->base.audio_ops->pin_eld_notify) {
/* audio drivers expect pipe = -1 to indicate Non-MST cases */ /* audio drivers expect pipe = -1 to indicate Non-MST cases */
if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST)) if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST))
pipe = -1; pipe = -1;
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
(int) port, (int) pipe); (int) port, (int) pipe);
} }
...@@ -880,7 +882,7 @@ static int i915_audio_component_get_eld(struct device *kdev, int port, ...@@ -880,7 +882,7 @@ static int i915_audio_component_get_eld(struct device *kdev, int port,
return ret; return ret;
} }
static const struct i915_audio_component_ops i915_audio_component_ops = { static const struct drm_audio_component_ops i915_audio_component_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.get_power = i915_audio_component_get_power, .get_power = i915_audio_component_get_power,
.put_power = i915_audio_component_put_power, .put_power = i915_audio_component_put_power,
...@@ -897,12 +899,12 @@ static int i915_audio_component_bind(struct device *i915_kdev, ...@@ -897,12 +899,12 @@ static int i915_audio_component_bind(struct device *i915_kdev,
struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
int i; int i;
if (WARN_ON(acomp->ops || acomp->dev)) if (WARN_ON(acomp->base.ops || acomp->base.dev))
return -EEXIST; return -EEXIST;
drm_modeset_lock_all(&dev_priv->drm); drm_modeset_lock_all(&dev_priv->drm);
acomp->ops = &i915_audio_component_ops; acomp->base.ops = &i915_audio_component_ops;
acomp->dev = i915_kdev; acomp->base.dev = i915_kdev;
BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS); BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++) for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
acomp->aud_sample_rate[i] = 0; acomp->aud_sample_rate[i] = 0;
...@@ -919,8 +921,8 @@ static void i915_audio_component_unbind(struct device *i915_kdev, ...@@ -919,8 +921,8 @@ static void i915_audio_component_unbind(struct device *i915_kdev,
struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev); struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
drm_modeset_lock_all(&dev_priv->drm); drm_modeset_lock_all(&dev_priv->drm);
acomp->ops = NULL; acomp->base.ops = NULL;
acomp->dev = NULL; acomp->base.dev = NULL;
dev_priv->audio_component = NULL; dev_priv->audio_component = NULL;
drm_modeset_unlock_all(&dev_priv->drm); drm_modeset_unlock_all(&dev_priv->drm);
} }
......
// SPDX-License-Identifier: MIT
// Copyright © 2014 Intel Corporation
#ifndef _DRM_AUDIO_COMPONENT_H_
#define _DRM_AUDIO_COMPONENT_H_
struct drm_audio_component;
/**
* struct drm_audio_component_ops - Ops implemented by DRM driver, called by hda driver
*/
struct drm_audio_component_ops {
/**
* @owner: drm module to pin down
*/
struct module *owner;
/**
* @get_power: get the POWER_DOMAIN_AUDIO power well
*
* Request the power well to be turned on.
*/
void (*get_power)(struct device *);
/**
* @put_power: put the POWER_DOMAIN_AUDIO power well
*
* Allow the power well to be turned off.
*/
void (*put_power)(struct device *);
/**
* @codec_wake_override: Enable/disable codec wake signal
*/
void (*codec_wake_override)(struct device *, bool enable);
/**
* @get_cdclk_freq: Get the Core Display Clock in kHz
*/
int (*get_cdclk_freq)(struct device *);
/**
* @sync_audio_rate: set n/cts based on the sample rate
*
* Called from audio driver. After audio driver sets the
* sample rate, it will call this function to set n/cts
*/
int (*sync_audio_rate)(struct device *, int port, int pipe, int rate);
/**
* @get_eld: fill the audio state and ELD bytes for the given port
*
* Called from audio driver to get the HDMI/DP audio state of the given
* digital port, and also fetch ELD bytes to the given pointer.
*
* It returns the byte size of the original ELD (not the actually
* copied size), zero for an invalid ELD, or a negative error code.
*
* Note that the returned size may be over @max_bytes. Then it
* implies that only a part of ELD has been copied to the buffer.
*/
int (*get_eld)(struct device *, int port, int pipe, bool *enabled,
unsigned char *buf, int max_bytes);
};
/**
* struct drm_audio_component_audio_ops - Ops implemented by hda driver, called by DRM driver
*/
struct drm_audio_component_audio_ops {
/**
* @audio_ptr: Pointer to be used in call to pin_eld_notify
*/
void *audio_ptr;
/**
* @pin_eld_notify: Notify the HDA driver that pin sense and/or ELD information has changed
*
* Called when the DRM driver has set up audio pipeline or has just
* begun to tear it down. This allows the HDA driver to update its
* status accordingly (even when the HDA controller is in power save
* mode).
*/
void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
/**
* @pin2port: Check and convert from pin node to port number
*
* Called by HDA driver to check and convert from the pin widget node
* number to a port number in the graphics side.
*/
int (*pin2port)(void *audio_ptr, int pin);
/**
* @master_bind: (Optional) component master bind callback
*
* Called at binding master component, for HDA codec-specific
* handling of dynamic binding.
*/
int (*master_bind)(struct device *dev, struct drm_audio_component *);
/**
* @master_unbind: (Optional) component master unbind callback
*
* Called at unbinding master component, for HDA codec-specific
* handling of dynamic unbinding.
*/
void (*master_unbind)(struct device *dev, struct drm_audio_component *);
};
/**
* struct drm_audio_component - Used for direct communication between DRM and hda drivers
*/
struct drm_audio_component {
/**
* @dev: DRM device, used as parameter for ops
*/
struct device *dev;
/**
* @ops: Ops implemented by DRM driver, called by hda driver
*/
const struct drm_audio_component_ops *ops;
/**
* @audio_ops: Ops implemented by hda driver, called by DRM driver
*/
const struct drm_audio_component_audio_ops *audio_ops;
};
#endif /* _DRM_AUDIO_COMPONENT_H_ */
...@@ -24,101 +24,26 @@ ...@@ -24,101 +24,26 @@
#ifndef _I915_COMPONENT_H_ #ifndef _I915_COMPONENT_H_
#define _I915_COMPONENT_H_ #define _I915_COMPONENT_H_
#include "drm_audio_component.h"
/* MAX_PORT is the number of port /* MAX_PORT is the number of port
* It must be sync with I915_MAX_PORTS defined i915_drv.h * It must be sync with I915_MAX_PORTS defined i915_drv.h
*/ */
#define MAX_PORTS 6 #define MAX_PORTS 6
/**
* struct i915_audio_component_ops - Ops implemented by i915 driver, called by hda driver
*/
struct i915_audio_component_ops {
/**
* @owner: i915 module
*/
struct module *owner;
/**
* @get_power: get the POWER_DOMAIN_AUDIO power well
*
* Request the power well to be turned on.
*/
void (*get_power)(struct device *);
/**
* @put_power: put the POWER_DOMAIN_AUDIO power well
*
* Allow the power well to be turned off.
*/
void (*put_power)(struct device *);
/**
* @codec_wake_override: Enable/disable codec wake signal
*/
void (*codec_wake_override)(struct device *, bool enable);
/**
* @get_cdclk_freq: Get the Core Display Clock in kHz
*/
int (*get_cdclk_freq)(struct device *);
/**
* @sync_audio_rate: set n/cts based on the sample rate
*
* Called from audio driver. After audio driver sets the
* sample rate, it will call this function to set n/cts
*/
int (*sync_audio_rate)(struct device *, int port, int pipe, int rate);
/**
* @get_eld: fill the audio state and ELD bytes for the given port
*
* Called from audio driver to get the HDMI/DP audio state of the given
* digital port, and also fetch ELD bytes to the given pointer.
*
* It returns the byte size of the original ELD (not the actually
* copied size), zero for an invalid ELD, or a negative error code.
*
* Note that the returned size may be over @max_bytes. Then it
* implies that only a part of ELD has been copied to the buffer.
*/
int (*get_eld)(struct device *, int port, int pipe, bool *enabled,
unsigned char *buf, int max_bytes);
};
/**
* struct i915_audio_component_audio_ops - Ops implemented by hda driver, called by i915 driver
*/
struct i915_audio_component_audio_ops {
/**
* @audio_ptr: Pointer to be used in call to pin_eld_notify
*/
void *audio_ptr;
/**
* @pin_eld_notify: Notify the HDA driver that pin sense and/or ELD information has changed
*
* Called when the i915 driver has set up audio pipeline or has just
* begun to tear it down. This allows the HDA driver to update its
* status accordingly (even when the HDA controller is in power save
* mode).
*/
void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
};
/** /**
* struct i915_audio_component - Used for direct communication between i915 and hda drivers * struct i915_audio_component - Used for direct communication between i915 and hda drivers
*/ */
struct i915_audio_component { struct i915_audio_component {
/** /**
* @dev: i915 device, used as parameter for ops * @base: the drm_audio_component base class
*/ */
struct device *dev; struct drm_audio_component base;
/** /**
* @aud_sample_rate: the array of audio sample rate per port * @aud_sample_rate: the array of audio sample rate per port
*/ */
int aud_sample_rate[MAX_PORTS]; int aud_sample_rate[MAX_PORTS];
/**
* @ops: Ops implemented by i915 driver, called by hda driver
*/
const struct i915_audio_component_ops *ops;
/**
* @audio_ops: Ops implemented by hda driver, called by i915 driver
*/
const struct i915_audio_component_audio_ops *audio_ops;
}; };
#endif /* _I915_COMPONENT_H_ */ #endif /* _I915_COMPONENT_H_ */
// SPDX-License-Identifier: GPL-2.0
// HD-Audio helpers to sync with DRM driver
#ifndef __SOUND_HDA_COMPONENT_H
#define __SOUND_HDA_COMPONENT_H
#include <drm/drm_audio_component.h>
#ifdef CONFIG_SND_HDA_COMPONENT
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
int dev_id, int rate);
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
bool *audio_enabled, char *buffer, int max_bytes);
int snd_hdac_acomp_init(struct hdac_bus *bus,
const struct drm_audio_component_audio_ops *aops,
int (*match_master)(struct device *, void *),
size_t extra_size);
int snd_hdac_acomp_exit(struct hdac_bus *bus);
int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
const struct drm_audio_component_audio_ops *ops);
#else
static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
{
return 0;
}
static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
{
return 0;
}
static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
hda_nid_t nid, int dev_id, int rate)
{
return 0;
}
static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
int dev_id, bool *audio_enabled,
char *buffer, int max_bytes)
{
return -ENODEV;
}
static inline int snd_hdac_acomp_init(struct hdac_bus *bus,
const struct drm_audio_component_audio_ops *aops,
int (*match_master)(struct device *, void *),
size_t extra_size)
{
return -ENODEV;
}
static inline int snd_hdac_acomp_exit(struct hdac_bus *bus)
{
return 0;
}
static inline int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
const struct drm_audio_component_audio_ops *ops)
{
return -ENODEV;
}
#endif
#endif /* __SOUND_HDA_COMPONENT_H */
...@@ -5,54 +5,23 @@ ...@@ -5,54 +5,23 @@
#ifndef __SOUND_HDA_I915_H #ifndef __SOUND_HDA_I915_H
#define __SOUND_HDA_I915_H #define __SOUND_HDA_I915_H
#include <drm/i915_component.h> #include "hda_component.h"
#ifdef CONFIG_SND_HDA_I915 #ifdef CONFIG_SND_HDA_I915
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
void snd_hdac_i915_set_bclk(struct hdac_bus *bus); void snd_hdac_i915_set_bclk(struct hdac_bus *bus);
int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
int dev_id, int rate);
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
bool *audio_enabled, char *buffer, int max_bytes);
int snd_hdac_i915_init(struct hdac_bus *bus); int snd_hdac_i915_init(struct hdac_bus *bus);
int snd_hdac_i915_exit(struct hdac_bus *bus);
int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *);
#else #else
static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
{
return 0;
}
static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
{
return 0;
}
static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus) static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
{ {
} }
static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
hda_nid_t nid, int dev_id, int rate)
{
return 0;
}
static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
int dev_id, bool *audio_enabled,
char *buffer, int max_bytes)
{
return -ENODEV;
}
static inline int snd_hdac_i915_init(struct hdac_bus *bus) static inline int snd_hdac_i915_init(struct hdac_bus *bus)
{ {
return -ENODEV; return -ENODEV;
} }
#endif
static inline int snd_hdac_i915_exit(struct hdac_bus *bus) static inline int snd_hdac_i915_exit(struct hdac_bus *bus)
{ {
return 0; return snd_hdac_acomp_exit(bus);
} }
static inline int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *ops)
{
return -ENODEV;
}
#endif
#endif /* __SOUND_HDA_I915_H */ #endif /* __SOUND_HDA_I915_H */
...@@ -360,9 +360,9 @@ struct hdac_bus { ...@@ -360,9 +360,9 @@ struct hdac_bus {
spinlock_t reg_lock; spinlock_t reg_lock;
struct mutex cmd_mutex; struct mutex cmd_mutex;
/* i915 component interface */ /* DRM component interface */
struct i915_audio_component *audio_component; struct drm_audio_component *audio_component;
int i915_power_refcount; int drm_power_refcount;
/* parameters required for enhanced capabilities */ /* parameters required for enhanced capabilities */
int num_streams; int num_streams;
......
...@@ -5,11 +5,12 @@ config SND_HDA_CORE ...@@ -5,11 +5,12 @@ config SND_HDA_CORE
config SND_HDA_DSP_LOADER config SND_HDA_DSP_LOADER
bool bool
config SND_HDA_COMPONENT
bool
config SND_HDA_I915 config SND_HDA_I915
bool bool
default y select SND_HDA_COMPONENT
depends on DRM_I915
depends on SND_HDA_CORE
config SND_HDA_EXT_CORE config SND_HDA_EXT_CORE
tristate tristate
......
...@@ -6,6 +6,7 @@ snd-hda-core-objs += trace.o ...@@ -6,6 +6,7 @@ snd-hda-core-objs += trace.o
CFLAGS_trace.o := -I$(src) CFLAGS_trace.o := -I$(src)
# for sync with i915 gfx driver # for sync with i915 gfx driver
snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += hdac_component.o
snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o
obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
......
// SPDX-License-Identifier: GPL-2.0
// hdac_component.c - routines for sync between HD-A core and DRM driver
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/component.h>
#include <sound/core.h>
#include <sound/hdaudio.h>
#include <sound/hda_component.h>
#include <sound/hda_register.h>
static void hdac_acomp_release(struct device *dev, void *res)
{
}
static struct drm_audio_component *hdac_get_acomp(struct device *dev)
{
return devres_find(dev, hdac_acomp_release, NULL, NULL);
}
/**
* snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
* @bus: HDA core bus
* @enable: enable or disable the wakeup
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with graphics driver.
*
* This function should be called during the chip reset, also called at
* resume for updating STATESTS register read.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
{
struct drm_audio_component *acomp = bus->audio_component;
if (!acomp || !acomp->ops)
return -ENODEV;
if (!acomp->ops->codec_wake_override)
return 0;
dev_dbg(bus->dev, "%s codec wakeup\n",
enable ? "enable" : "disable");
acomp->ops->codec_wake_override(acomp->dev, enable);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
/**
* snd_hdac_display_power - Power up / down the power refcount
* @bus: HDA core bus
* @enable: power up or down
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with graphics driver.
*
* This function manages a refcount and calls the get_power() and
* put_power() ops accordingly, toggling the codec wakeup, too.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
{
struct drm_audio_component *acomp = bus->audio_component;
if (!acomp || !acomp->ops)
return -ENODEV;
dev_dbg(bus->dev, "display power %s\n",
enable ? "enable" : "disable");
if (enable) {
if (!bus->drm_power_refcount++) {
if (acomp->ops->get_power)
acomp->ops->get_power(acomp->dev);
snd_hdac_set_codec_wakeup(bus, true);
snd_hdac_set_codec_wakeup(bus, false);
}
} else {
WARN_ON(!bus->drm_power_refcount);
if (!--bus->drm_power_refcount)
if (acomp->ops->put_power)
acomp->ops->put_power(acomp->dev);
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
/**
* snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
* @codec: HDA codec
* @nid: the pin widget NID
* @dev_id: device identifier
* @rate: the sample rate to set
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with graphics driver.
*
* This function sets N/CTS value based on the given sample rate.
* Returns zero for success, or a negative error code.
*/
int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
int dev_id, int rate)
{
struct hdac_bus *bus = codec->bus;
struct drm_audio_component *acomp = bus->audio_component;
int port, pipe;
if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
return -ENODEV;
port = nid;
if (acomp->audio_ops && acomp->audio_ops->pin2port) {
port = acomp->audio_ops->pin2port(codec, nid);
if (port < 0)
return -EINVAL;
}
pipe = dev_id;
return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
}
EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
/**
* snd_hdac_acomp_get_eld - Get the audio state and ELD via component
* @codec: HDA codec
* @nid: the pin widget NID
* @dev_id: device identifier
* @audio_enabled: the pointer to store the current audio state
* @buffer: the buffer pointer to store ELD bytes
* @max_bytes: the max bytes to be stored on @buffer
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with graphics driver.
*
* This function queries the current state of the audio on the given
* digital port and fetches the ELD bytes onto the given buffer.
* It returns the number of bytes for the total ELD data, zero for
* invalid ELD, or a negative error code.
*
* The return size is the total bytes required for the whole ELD bytes,
* thus it may be over @max_bytes. If it's over @max_bytes, it implies
* that only a part of ELD bytes have been fetched.
*/
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
bool *audio_enabled, char *buffer, int max_bytes)
{
struct hdac_bus *bus = codec->bus;
struct drm_audio_component *acomp = bus->audio_component;
int port, pipe;
if (!acomp || !acomp->ops || !acomp->ops->get_eld)
return -ENODEV;
port = nid;
if (acomp->audio_ops && acomp->audio_ops->pin2port) {
port = acomp->audio_ops->pin2port(codec, nid);
if (port < 0)
return -EINVAL;
}
pipe = dev_id;
return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
buffer, max_bytes);
}
EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
static int hdac_component_master_bind(struct device *dev)
{
struct drm_audio_component *acomp = hdac_get_acomp(dev);
int ret;
if (WARN_ON(!acomp))
return -EINVAL;
ret = component_bind_all(dev, acomp);
if (ret < 0)
return ret;
if (WARN_ON(!(acomp->dev && acomp->ops))) {
ret = -EINVAL;
goto out_unbind;
}
/* pin the module to avoid dynamic unbinding, but only if given */
if (!try_module_get(acomp->ops->owner)) {
ret = -ENODEV;
goto out_unbind;
}
if (acomp->audio_ops && acomp->audio_ops->master_bind) {
ret = acomp->audio_ops->master_bind(dev, acomp);
if (ret < 0)
goto module_put;
}
return 0;
module_put:
module_put(acomp->ops->owner);
out_unbind:
component_unbind_all(dev, acomp);
return ret;
}
static void hdac_component_master_unbind(struct device *dev)
{
struct drm_audio_component *acomp = hdac_get_acomp(dev);
if (acomp->audio_ops && acomp->audio_ops->master_unbind)
acomp->audio_ops->master_unbind(dev, acomp);
module_put(acomp->ops->owner);
component_unbind_all(dev, acomp);
WARN_ON(acomp->ops || acomp->dev);
}
static const struct component_master_ops hdac_component_master_ops = {
.bind = hdac_component_master_bind,
.unbind = hdac_component_master_unbind,
};
/**
* snd_hdac_acomp_register_notifier - Register audio component ops
* @bus: HDA core bus
* @aops: audio component ops
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with graphics driver.
*
* This function sets the given ops to be called by the graphics driver.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
const struct drm_audio_component_audio_ops *aops)
{
if (!bus->audio_component)
return -ENODEV;
bus->audio_component->audio_ops = aops;
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier);
/**
* snd_hdac_acomp_init - Initialize audio component
* @bus: HDA core bus
* @match_master: match function for finding components
* @extra_size: Extra bytes to allocate
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with graphics driver.
*
* This function initializes and sets up the audio component to communicate
* with graphics driver.
*
* Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
* binding with the DRM component. Each caller needs to sync via master_bind
* audio_ops.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_acomp_init(struct hdac_bus *bus,
const struct drm_audio_component_audio_ops *aops,
int (*match_master)(struct device *, void *),
size_t extra_size)
{
struct component_match *match = NULL;
struct device *dev = bus->dev;
struct drm_audio_component *acomp;
int ret;
if (WARN_ON(hdac_get_acomp(dev)))
return -EBUSY;
acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
GFP_KERNEL);
if (!acomp)
return -ENOMEM;
acomp->audio_ops = aops;
bus->audio_component = acomp;
devres_add(dev, acomp);
component_match_add(dev, &match, match_master, bus);
ret = component_master_add_with_match(dev, &hdac_component_master_ops,
match);
if (ret < 0)
goto out_err;
return 0;
out_err:
bus->audio_component = NULL;
devres_destroy(dev, hdac_acomp_release, NULL, NULL);
dev_info(dev, "failed to add audio component master (%d)\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
/**
* snd_hdac_acomp_exit - Finalize audio component
* @bus: HDA core bus
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with graphics driver.
*
* This function releases the audio component that has been used.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_acomp_exit(struct hdac_bus *bus)
{
struct device *dev = bus->dev;
struct drm_audio_component *acomp = bus->audio_component;
if (!acomp)
return 0;
WARN_ON(bus->drm_power_refcount);
if (bus->drm_power_refcount > 0 && acomp->ops)
acomp->ops->put_power(acomp->dev);
component_master_del(dev, &hdac_component_master_ops);
bus->audio_component = NULL;
devres_destroy(dev, hdac_acomp_release, NULL, NULL);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);
...@@ -15,89 +15,11 @@ ...@@ -15,89 +15,11 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/component.h>
#include <drm/i915_component.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/hdaudio.h> #include <sound/hdaudio.h>
#include <sound/hda_i915.h> #include <sound/hda_i915.h>
#include <sound/hda_register.h> #include <sound/hda_register.h>
static struct i915_audio_component *hdac_acomp;
/**
* snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
* @bus: HDA core bus
* @enable: enable or disable the wakeup
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with i915 graphics.
*
* This function should be called during the chip reset, also called at
* resume for updating STATESTS register read.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
{
struct i915_audio_component *acomp = bus->audio_component;
if (!acomp || !acomp->ops)
return -ENODEV;
if (!acomp->ops->codec_wake_override) {
dev_warn(bus->dev,
"Invalid codec wake callback\n");
return 0;
}
dev_dbg(bus->dev, "%s codec wakeup\n",
enable ? "enable" : "disable");
acomp->ops->codec_wake_override(acomp->dev, enable);
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
/**
* snd_hdac_display_power - Power up / down the power refcount
* @bus: HDA core bus
* @enable: power up or down
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with i915 graphics.
*
* This function manages a refcount and calls the i915 get_power() and
* put_power() ops accordingly, toggling the codec wakeup, too.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
{
struct i915_audio_component *acomp = bus->audio_component;
if (!acomp || !acomp->ops)
return -ENODEV;
dev_dbg(bus->dev, "display power %s\n",
enable ? "enable" : "disable");
if (enable) {
if (!bus->i915_power_refcount++) {
acomp->ops->get_power(acomp->dev);
snd_hdac_set_codec_wakeup(bus, true);
snd_hdac_set_codec_wakeup(bus, false);
}
} else {
WARN_ON(!bus->i915_power_refcount);
if (!--bus->i915_power_refcount)
acomp->ops->put_power(acomp->dev);
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
((pci)->device == 0x0c0c) || \ ((pci)->device == 0x0c0c) || \
((pci)->device == 0x0d0c) || \ ((pci)->device == 0x0d0c) || \
...@@ -119,7 +41,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_display_power); ...@@ -119,7 +41,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_display_power);
*/ */
void snd_hdac_i915_set_bclk(struct hdac_bus *bus) void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
{ {
struct i915_audio_component *acomp = bus->audio_component; struct drm_audio_component *acomp = bus->audio_component;
struct pci_dev *pci = to_pci_dev(bus->dev); struct pci_dev *pci = to_pci_dev(bus->dev);
int cdclk_freq; int cdclk_freq;
unsigned int bclk_m, bclk_n; unsigned int bclk_m, bclk_n;
...@@ -158,181 +80,11 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus) ...@@ -158,181 +80,11 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
} }
EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk);
/* There is a fixed mapping between audio pin node and display port. static int i915_component_master_match(struct device *dev, void *data)
* on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
* Pin Widget 5 - PORT B (port = 1 in i915 driver)
* Pin Widget 6 - PORT C (port = 2 in i915 driver)
* Pin Widget 7 - PORT D (port = 3 in i915 driver)
*
* on VLV, ILK:
* Pin Widget 4 - PORT B (port = 1 in i915 driver)
* Pin Widget 5 - PORT C (port = 2 in i915 driver)
* Pin Widget 6 - PORT D (port = 3 in i915 driver)
*/
static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
{ {
int base_nid;
switch (codec->vendor_id) {
case 0x80860054: /* ILK */
case 0x80862804: /* ILK */
case 0x80862882: /* VLV */
base_nid = 3;
break;
default:
base_nid = 4;
break;
}
if (WARN_ON(pin_nid <= base_nid || pin_nid > base_nid + 3))
return -1;
return pin_nid - base_nid;
}
/**
* snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
* @codec: HDA codec
* @nid: the pin widget NID
* @dev_id: device identifier
* @rate: the sample rate to set
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with i915 graphics.
*
* This function sets N/CTS value based on the given sample rate.
* Returns zero for success, or a negative error code.
*/
int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
int dev_id, int rate)
{
struct hdac_bus *bus = codec->bus;
struct i915_audio_component *acomp = bus->audio_component;
int port, pipe;
if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
return -ENODEV;
port = pin2port(codec, nid);
if (port < 0)
return -EINVAL;
pipe = dev_id;
return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
}
EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
/**
* snd_hdac_acomp_get_eld - Get the audio state and ELD via component
* @codec: HDA codec
* @nid: the pin widget NID
* @dev_id: device identifier
* @audio_enabled: the pointer to store the current audio state
* @buffer: the buffer pointer to store ELD bytes
* @max_bytes: the max bytes to be stored on @buffer
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with i915 graphics.
*
* This function queries the current state of the audio on the given
* digital port and fetches the ELD bytes onto the given buffer.
* It returns the number of bytes for the total ELD data, zero for
* invalid ELD, or a negative error code.
*
* The return size is the total bytes required for the whole ELD bytes,
* thus it may be over @max_bytes. If it's over @max_bytes, it implies
* that only a part of ELD bytes have been fetched.
*/
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
bool *audio_enabled, char *buffer, int max_bytes)
{
struct hdac_bus *bus = codec->bus;
struct i915_audio_component *acomp = bus->audio_component;
int port, pipe;
if (!acomp || !acomp->ops || !acomp->ops->get_eld)
return -ENODEV;
port = pin2port(codec, nid);
if (port < 0)
return -EINVAL;
pipe = dev_id;
return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
buffer, max_bytes);
}
EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
static int hdac_component_master_bind(struct device *dev)
{
struct i915_audio_component *acomp = hdac_acomp;
int ret;
ret = component_bind_all(dev, acomp);
if (ret < 0)
return ret;
if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
ret = -EINVAL;
goto out_unbind;
}
/*
* Atm, we don't support dynamic unbinding initiated by the child
* component, so pin its containing module until we unbind.
*/
if (!try_module_get(acomp->ops->owner)) {
ret = -ENODEV;
goto out_unbind;
}
return 0;
out_unbind:
component_unbind_all(dev, acomp);
return ret;
}
static void hdac_component_master_unbind(struct device *dev)
{
struct i915_audio_component *acomp = hdac_acomp;
module_put(acomp->ops->owner);
component_unbind_all(dev, acomp);
WARN_ON(acomp->ops || acomp->dev);
}
static const struct component_master_ops hdac_component_master_ops = {
.bind = hdac_component_master_bind,
.unbind = hdac_component_master_unbind,
};
static int hdac_component_master_match(struct device *dev, void *data)
{
/* i915 is the only supported component */
return !strcmp(dev->driver->name, "i915"); return !strcmp(dev->driver->name, "i915");
} }
/**
* snd_hdac_i915_register_notifier - Register i915 audio component ops
* @aops: i915 audio component ops
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with i915 graphics.
*
* This function sets the given ops to be called by the i915 graphics driver.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops)
{
if (!hdac_acomp)
return -ENODEV;
hdac_acomp->audio_ops = aops;
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier);
/* check whether intel graphics is present */ /* check whether intel graphics is present */
static bool i915_gfx_present(void) static bool i915_gfx_present(void)
{ {
...@@ -359,83 +111,26 @@ static bool i915_gfx_present(void) ...@@ -359,83 +111,26 @@ static bool i915_gfx_present(void)
*/ */
int snd_hdac_i915_init(struct hdac_bus *bus) int snd_hdac_i915_init(struct hdac_bus *bus)
{ {
struct component_match *match = NULL; struct drm_audio_component *acomp;
struct device *dev = bus->dev; int err;
struct i915_audio_component *acomp;
int ret;
if (WARN_ON(hdac_acomp))
return -EBUSY;
if (!i915_gfx_present()) if (!i915_gfx_present())
return -ENODEV; return -ENODEV;
acomp = kzalloc(sizeof(*acomp), GFP_KERNEL); err = snd_hdac_acomp_init(bus, NULL,
i915_component_master_match,
sizeof(struct i915_audio_component) - sizeof(*acomp));
if (err < 0)
return err;
acomp = bus->audio_component;
if (!acomp) if (!acomp)
return -ENOMEM; return -ENODEV;
bus->audio_component = acomp; if (!acomp->ops)
hdac_acomp = acomp; request_module("i915");
component_match_add(dev, &match, hdac_component_master_match, bus);
ret = component_master_add_with_match(dev, &hdac_component_master_ops,
match);
if (ret < 0)
goto out_err;
/*
* Atm, we don't support deferring the component binding, so make sure
* i915 is loaded and that the binding successfully completes.
*/
request_module("i915");
if (!acomp->ops) { if (!acomp->ops) {
ret = -ENODEV; snd_hdac_acomp_exit(bus);
goto out_master_del; return -ENODEV;
} }
dev_dbg(dev, "bound to i915 component master\n");
return 0; return 0;
out_master_del:
component_master_del(dev, &hdac_component_master_ops);
out_err:
kfree(acomp);
bus->audio_component = NULL;
hdac_acomp = NULL;
dev_info(dev, "failed to add i915 component master (%d)\n", ret);
return ret;
} }
EXPORT_SYMBOL_GPL(snd_hdac_i915_init); EXPORT_SYMBOL_GPL(snd_hdac_i915_init);
/**
* snd_hdac_i915_exit - Finalize i915 audio component
* @bus: HDA core bus
*
* This function is supposed to be used only by a HD-audio controller
* driver that needs the interaction with i915 graphics.
*
* This function releases the i915 audio component that has been used.
*
* Returns zero for success or a negative error code.
*/
int snd_hdac_i915_exit(struct hdac_bus *bus)
{
struct device *dev = bus->dev;
struct i915_audio_component *acomp = bus->audio_component;
if (!acomp)
return 0;
WARN_ON(bus->i915_power_refcount);
if (bus->i915_power_refcount > 0 && acomp->ops)
acomp->ops->put_power(acomp->dev);
component_master_del(dev, &hdac_component_master_ops);
kfree(acomp);
bus->audio_component = NULL;
hdac_acomp = NULL;
return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_i915_exit);
...@@ -177,13 +177,13 @@ struct hdmi_spec { ...@@ -177,13 +177,13 @@ struct hdmi_spec {
/* i915/powerwell (Haswell+/Valleyview+) specific */ /* i915/powerwell (Haswell+/Valleyview+) specific */
bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */ bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */
struct i915_audio_component_audio_ops i915_audio_ops; struct drm_audio_component_audio_ops drm_audio_ops;
struct hdac_chmap chmap; struct hdac_chmap chmap;
hda_nid_t vendor_nid; hda_nid_t vendor_nid;
}; };
#ifdef CONFIG_SND_HDA_I915 #ifdef CONFIG_SND_HDA_COMPONENT
static inline bool codec_has_acomp(struct hda_codec *codec) static inline bool codec_has_acomp(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
...@@ -2288,7 +2288,7 @@ static void generic_hdmi_free(struct hda_codec *codec) ...@@ -2288,7 +2288,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
int pin_idx, pcm_idx; int pin_idx, pcm_idx;
if (codec_has_acomp(codec)) if (codec_has_acomp(codec))
snd_hdac_i915_register_notifier(NULL); snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
...@@ -2471,6 +2471,38 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, ...@@ -2471,6 +2471,38 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
snd_hda_codec_set_power_to_all(codec, fg, power_state); snd_hda_codec_set_power_to_all(codec, fg, power_state);
} }
/* There is a fixed mapping between audio pin node and display port.
* on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
* Pin Widget 5 - PORT B (port = 1 in i915 driver)
* Pin Widget 6 - PORT C (port = 2 in i915 driver)
* Pin Widget 7 - PORT D (port = 3 in i915 driver)
*
* on VLV, ILK:
* Pin Widget 4 - PORT B (port = 1 in i915 driver)
* Pin Widget 5 - PORT C (port = 2 in i915 driver)
* Pin Widget 6 - PORT D (port = 3 in i915 driver)
*/
static int intel_base_nid(struct hda_codec *codec)
{
switch (codec->core.vendor_id) {
case 0x80860054: /* ILK */
case 0x80862804: /* ILK */
case 0x80862882: /* VLV */
return 4;
default:
return 5;
}
}
static int intel_pin2port(void *audio_ptr, int pin_nid)
{
int base_nid = intel_base_nid(audio_ptr);
if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
return -1;
return pin_nid - base_nid + 1; /* intel port is 1-based */
}
static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
{ {
struct hda_codec *codec = audio_ptr; struct hda_codec *codec = audio_ptr;
...@@ -2481,16 +2513,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) ...@@ -2481,16 +2513,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
if (port < 1 || port > 3) if (port < 1 || port > 3)
return; return;
switch (codec->core.vendor_id) { pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */
case 0x80860054: /* ILK */
case 0x80862804: /* ILK */
case 0x80862882: /* VLV */
pin_nid = port + 0x03;
break;
default:
pin_nid = port + 0x04;
break;
}
/* skip notification during system suspend (but not in runtime PM); /* skip notification during system suspend (but not in runtime PM);
* the state will be updated at resume * the state will be updated at resume
...@@ -2511,14 +2534,16 @@ static void register_i915_notifier(struct hda_codec *codec) ...@@ -2511,14 +2534,16 @@ static void register_i915_notifier(struct hda_codec *codec)
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
spec->use_acomp_notifier = true; spec->use_acomp_notifier = true;
spec->i915_audio_ops.audio_ptr = codec; spec->drm_audio_ops.audio_ptr = codec;
/* intel_audio_codec_enable() or intel_audio_codec_disable() /* intel_audio_codec_enable() or intel_audio_codec_disable()
* will call pin_eld_notify with using audio_ptr pointer * will call pin_eld_notify with using audio_ptr pointer
* We need make sure audio_ptr is really setup * We need make sure audio_ptr is really setup
*/ */
wmb(); wmb();
spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify; spec->drm_audio_ops.pin2port = intel_pin2port;
snd_hdac_i915_register_notifier(&spec->i915_audio_ops); spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify;
snd_hdac_acomp_register_notifier(&codec->bus->core,
&spec->drm_audio_ops);
} }
/* setup_stream ops override for HSW+ */ /* setup_stream ops override for HSW+ */
......
...@@ -1530,6 +1530,11 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, ...@@ -1530,6 +1530,11 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
return ret; return ret;
} }
static int hdac_hdmi_pin2port(void *aptr, int pin)
{
return pin - 4; /* map NID 0x05 -> port #1 */
}
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
{ {
struct hdac_device *hdev = aptr; struct hdac_device *hdev = aptr;
...@@ -1583,7 +1588,8 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) ...@@ -1583,7 +1588,8 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
} }
static struct i915_audio_component_audio_ops aops = { static struct drm_audio_component_audio_ops aops = {
.pin2port = hdac_hdmi_pin2port,
.pin_eld_notify = hdac_hdmi_eld_notify_cb, .pin_eld_notify = hdac_hdmi_eld_notify_cb,
}; };
...@@ -1812,7 +1818,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component) ...@@ -1812,7 +1818,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
return ret; return ret;
aops.audio_ptr = hdev; aops.audio_ptr = hdev;
ret = snd_hdac_i915_register_notifier(&aops); ret = snd_hdac_acomp_register_notifier(hdev->bus, &aops);
if (ret < 0) { if (ret < 0) {
dev_err(&hdev->dev, "notifier register failed: err: %d\n", ret); dev_err(&hdev->dev, "notifier register failed: err: %d\n", ret);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment