Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a9b13dd authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/hda-core-intel' into topic/hda-acomp

parents c5a59d24 cb04ba33
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -188,6 +188,11 @@ struct hdac_driver {
	const struct hda_device_id *id_table;
	int (*match)(struct hdac_device *dev, struct hdac_driver *drv);
	void (*unsol_event)(struct hdac_device *dev, unsigned int event);

	/* fields used by ext bus APIs */
	int (*probe)(struct hdac_device *dev);
	int (*remove)(struct hdac_device *dev);
	void (*shutdown)(struct hdac_device *dev);
};

#define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver)
@@ -208,6 +213,14 @@ struct hdac_bus_ops {
	int (*link_power)(struct hdac_bus *bus, bool enable);
};

/*
 * ops used for ASoC HDA codec drivers
 */
struct hdac_ext_bus_ops {
	int (*hdev_attach)(struct hdac_device *hdev);
	int (*hdev_detach)(struct hdac_device *hdev);
};

/*
 * Lowlevel I/O operators
 */
@@ -250,11 +263,17 @@ struct hdac_rb {
 * @mlcap: MultiLink capabilities pointer
 * @gtscap: gts capabilities pointer
 * @drsmcap: dma resume capabilities pointer
 * @num_streams: streams supported
 * @idx: HDA link index
 * @hlink_list: link list of HDA links
 * @lock: lock for link mgmt
 * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
 */
struct hdac_bus {
	struct device *dev;
	const struct hdac_bus_ops *ops;
	const struct hdac_io_ops *io_ops;
	const struct hdac_ext_bus_ops *ext_ops;

	/* h/w resources */
	unsigned long addr;
@@ -317,6 +336,16 @@ struct hdac_bus {
	/* i915 component interface */
	struct i915_audio_component *audio_component;
	int i915_power_refcount;

	/* parameters required for enhanced capabilities */
	int num_streams;
	int idx;

	struct list_head hlink_list;

	struct mutex lock;
	bool cmd_dma_state;

};

int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
+29 −94
Original line number Diff line number Diff line
@@ -4,38 +4,16 @@

#include <sound/hdaudio.h>

/**
 * hdac_ext_bus: HDAC extended bus for extended HDA caps
 *
 * @bus: hdac bus
 * @num_streams: streams supported
 * @hlink_list: link list of HDA links
 * @lock: lock for link mgmt
 * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
 */
struct hdac_ext_bus {
	struct hdac_bus bus;
	int num_streams;
	int idx;

	struct list_head hlink_list;

	struct mutex lock;
	bool cmd_dma_state;
};

int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev,
int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
		      const struct hdac_bus_ops *ops,
		      const struct hdac_io_ops *io_ops);
		      const struct hdac_io_ops *io_ops,
		      const struct hdac_ext_bus_ops *ext_ops);

void snd_hdac_ext_bus_exit(struct hdac_ext_bus *sbus);
int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *sbus, int addr);
void snd_hdac_ext_bus_exit(struct hdac_bus *bus);
int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
						struct hdac_device *hdev);
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev);
void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);

#define ebus_to_hbus(ebus)	(&(ebus)->bus)
#define hbus_to_ebus(_bus) \
	container_of(_bus, struct hdac_ext_bus, bus)
void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus);

#define HDA_CODEC_REV_EXT_ENTRY(_vid, _rev, _name, drv_data) \
	{ .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
@@ -44,14 +22,14 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
#define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \
	HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data)

void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable);
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable);
void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable);
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable);

void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *chip,
void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip,
				 bool enable, int index);

int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *bus);
struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *bus,
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus);
struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
						const char *codec_name);

enum hdac_ext_stream_type {
@@ -100,28 +78,28 @@ struct hdac_ext_stream {
#define stream_to_hdac_ext_stream(s) \
	container_of(s, struct hdac_ext_stream, hstream)

void snd_hdac_ext_stream_init(struct hdac_ext_bus *bus,
void snd_hdac_ext_stream_init(struct hdac_bus *bus,
				struct hdac_ext_stream *stream, int idx,
				int direction, int tag);
int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
		int num_stream, int dir);
void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus);
void snd_hdac_link_free_all(struct hdac_ext_bus *ebus);
struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_ext_bus *bus,
void snd_hdac_stream_free_all(struct hdac_bus *bus);
void snd_hdac_link_free_all(struct hdac_bus *bus);
struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
					   struct snd_pcm_substream *substream,
					   int type);
void snd_hdac_ext_stream_release(struct hdac_ext_stream *azx_dev, int type);
void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *bus,
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
				struct hdac_ext_stream *azx_dev, bool decouple);
void snd_hdac_ext_stop_streams(struct hdac_ext_bus *sbus);
void snd_hdac_ext_stop_streams(struct hdac_bus *bus);

int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
				 struct hdac_ext_stream *stream, u32 value);
int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
				 struct hdac_ext_stream *stream);
void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
				bool enable, int index);
int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
				struct hdac_ext_stream *stream, u32 value);
int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value);

@@ -144,17 +122,15 @@ struct hdac_ext_link {

int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus);
int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus);
int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus);
int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus);
void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
				 int stream);
void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
				 int stream);

int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
				struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
				struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link);
int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link);

/* update register macro */
#define snd_hdac_updatel(addr, reg, mask, val)		\
@@ -181,53 +157,12 @@ struct hda_dai_map {
	u32	maxbps;
};

#define HDA_MAX_NIDS 16

/**
 * struct hdac_ext_device - HDAC Ext device
 *
 * @hdac: hdac core device
 * @nid_list - the dai map which matches the dai-name with the nid
 * @map_cur_idx - the idx in use in dai_map
 * @ops - the hda codec ops common to all codec drivers
 * @pvt_data - private data, for asoc contains asoc codec object
 */
struct hdac_ext_device {
	struct hdac_device hdev;
	struct hdac_ext_bus *ebus;

	/* soc-dai to nid map */
	struct hda_dai_map nid_list[HDA_MAX_NIDS];
	unsigned int map_cur_idx;

	/* codec ops */
	struct hdac_ext_codec_ops ops;

	struct snd_card *card;
	void *scodec;
	void *private_data;
};

struct hdac_ext_dma_params {
	u32 format;
	u8 stream_tag;
};
#define to_ehdac_device(dev) (container_of((dev), \
				 struct hdac_ext_device, hdev))
/*
 * HD-audio codec base driver
 */
struct hdac_ext_driver {
	struct hdac_driver hdac;

	int	(*probe)(struct hdac_ext_device *dev);
	int	(*remove)(struct hdac_ext_device *dev);
	void	(*shutdown)(struct hdac_ext_device *dev);
};

int snd_hda_ext_driver_register(struct hdac_ext_driver *drv);
void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv);

#define to_ehdac_driver(_drv) container_of(_drv, struct hdac_ext_driver, hdac)
int snd_hda_ext_driver_register(struct hdac_driver *drv);
void snd_hda_ext_driver_unregister(struct hdac_driver *drv);

#endif /* __SOUND_HDAUDIO_EXT_H */
+35 −45
Original line number Diff line number Diff line
@@ -87,9 +87,10 @@ static const struct hdac_io_ops hdac_ext_default_io = {
 *
 * Returns 0 if successful, or a negative error code.
 */
int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
			const struct hdac_bus_ops *ops,
			const struct hdac_io_ops *io_ops)
			const struct hdac_io_ops *io_ops,
			const struct hdac_ext_bus_ops *ext_ops)
{
	int ret;
	static int idx;
@@ -98,15 +99,16 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
	if (io_ops == NULL)
		io_ops = &hdac_ext_default_io;

	ret = snd_hdac_bus_init(&ebus->bus, dev, ops, io_ops);
	ret = snd_hdac_bus_init(bus, dev, ops, io_ops);
	if (ret < 0)
		return ret;

	INIT_LIST_HEAD(&ebus->hlink_list);
	ebus->idx = idx++;
	bus->ext_ops = ext_ops;
	INIT_LIST_HEAD(&bus->hlink_list);
	bus->idx = idx++;

	mutex_init(&ebus->lock);
	ebus->cmd_dma_state = true;
	mutex_init(&bus->lock);
	bus->cmd_dma_state = true;

	return 0;
}
@@ -116,10 +118,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
 * snd_hdac_ext_bus_exit - clean up a HD-audio extended bus
 * @ebus: the pointer to extended bus object
 */
void snd_hdac_ext_bus_exit(struct hdac_ext_bus *ebus)
void snd_hdac_ext_bus_exit(struct hdac_bus *bus)
{
	snd_hdac_bus_exit(&ebus->bus);
	WARN_ON(!list_empty(&ebus->hlink_list));
	snd_hdac_bus_exit(bus);
	WARN_ON(!list_empty(&bus->hlink_list));
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit);

@@ -135,21 +137,15 @@ static void default_release(struct device *dev)
 *
 * Returns zero for success or a negative error code.
 */
int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
					struct hdac_device *hdev)
{
	struct hdac_ext_device *edev;
	struct hdac_device *hdev = NULL;
	struct hdac_bus *bus = ebus_to_hbus(ebus);
	char name[15];
	int ret;

	edev = kzalloc(sizeof(*edev), GFP_KERNEL);
	if (!edev)
		return -ENOMEM;
	hdev = &edev->hdev;
	edev->ebus = ebus;
	hdev->bus = bus;

	snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
	snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr);

	ret  = snd_hdac_device_init(hdev, bus, name, addr);
	if (ret < 0) {
@@ -176,10 +172,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
 */
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
{
	struct hdac_ext_device *edev = to_ehdac_device(hdev);

	snd_hdac_device_exit(hdev);
	kfree(edev);
	kfree(hdev);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);

@@ -188,14 +182,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
 *
 * @ebus: HD-audio extended bus
 */
void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus)
void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus)
{
	struct hdac_device *codec, *__codec;
	/*
	 * we need to remove all the codec devices objects created in the
	 * snd_hdac_ext_bus_device_init
	 */
	list_for_each_entry_safe(codec, __codec, &ebus->bus.codec_list, list) {
	list_for_each_entry_safe(codec, __codec, &bus->codec_list, list) {
		snd_hdac_device_unregister(codec);
		put_device(&codec->dev);
	}
@@ -204,35 +198,31 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
#define dev_to_hdac(dev) (container_of((dev), \
			struct hdac_device, dev))

static inline struct hdac_ext_driver *get_edrv(struct device *dev)
static inline struct hdac_driver *get_hdrv(struct device *dev)
{
	struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver);
	struct hdac_ext_driver *edrv = to_ehdac_driver(hdrv);

	return edrv;
	return hdrv;
}

static inline struct hdac_ext_device *get_edev(struct device *dev)
static inline struct hdac_device *get_hdev(struct device *dev)
{
	struct hdac_device *hdev = dev_to_hdac_dev(dev);
	struct hdac_ext_device *edev = to_ehdac_device(hdev);

	return edev;
	return hdev;
}

static int hda_ext_drv_probe(struct device *dev)
{
	return (get_edrv(dev))->probe(get_edev(dev));
	return (get_hdrv(dev))->probe(get_hdev(dev));
}

static int hdac_ext_drv_remove(struct device *dev)
{
	return (get_edrv(dev))->remove(get_edev(dev));
	return (get_hdrv(dev))->remove(get_hdev(dev));
}

static void hdac_ext_drv_shutdown(struct device *dev)
{
	return (get_edrv(dev))->shutdown(get_edev(dev));
	return (get_hdrv(dev))->shutdown(get_hdev(dev));
}

/**
@@ -240,20 +230,20 @@ static void hdac_ext_drv_shutdown(struct device *dev)
 *
 * @drv: ext hda driver structure
 */
int snd_hda_ext_driver_register(struct hdac_ext_driver *drv)
int snd_hda_ext_driver_register(struct hdac_driver *drv)
{
	drv->hdac.type = HDA_DEV_ASOC;
	drv->hdac.driver.bus = &snd_hda_bus_type;
	drv->type = HDA_DEV_ASOC;
	drv->driver.bus = &snd_hda_bus_type;
	/* we use default match */

	if (drv->probe)
		drv->hdac.driver.probe = hda_ext_drv_probe;
		drv->driver.probe = hda_ext_drv_probe;
	if (drv->remove)
		drv->hdac.driver.remove = hdac_ext_drv_remove;
		drv->driver.remove = hdac_ext_drv_remove;
	if (drv->shutdown)
		drv->hdac.driver.shutdown = hdac_ext_drv_shutdown;
		drv->driver.shutdown = hdac_ext_drv_shutdown;

	return driver_register(&drv->hdac.driver);
	return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);

@@ -262,8 +252,8 @@ EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
 *
 * @drv: ext hda driver structure
 */
void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv)
void snd_hda_ext_driver_unregister(struct hdac_driver *drv)
{
	driver_unregister(&drv->hdac.driver);
	driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);
+35 −29
Original line number Diff line number Diff line
@@ -39,9 +39,8 @@
 * @ebus: HD-audio extended core bus
 * @enable: flag to turn on/off the capability
 */
void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable)
void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
{
	struct hdac_bus *bus = &ebus->bus;

	if (!bus->ppcap) {
		dev_err(bus->dev, "Address of PP capability is NULL");
@@ -60,9 +59,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
 * @ebus: HD-audio extended core bus
 * @enable: flag to enable/disable interrupt
 */
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable)
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
{
	struct hdac_bus *bus = &ebus->bus;

	if (!bus->ppcap) {
		dev_err(bus->dev, "Address of PP capability is NULL\n");
@@ -89,12 +87,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
 * in hlink_list of extended hdac bus
 * Note: this will be freed on bus exit by driver
 */
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
{
	int idx;
	u32 link_count;
	struct hdac_ext_link *hlink;
	struct hdac_bus *bus = &ebus->bus;

	link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;

@@ -114,7 +111,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
		/* since link in On, update the ref */
		hlink->ref_count = 1;

		list_add_tail(&hlink->list, &ebus->hlink_list);
		list_add_tail(&hlink->list, &bus->hlink_list);
	}

	return 0;
@@ -127,12 +124,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
 * @ebus: HD-audio ext core bus
 */

void snd_hdac_link_free_all(struct hdac_ext_bus *ebus)
void snd_hdac_link_free_all(struct hdac_bus *bus)
{
	struct hdac_ext_link *l;

	while (!list_empty(&ebus->hlink_list)) {
		l = list_first_entry(&ebus->hlink_list, struct hdac_ext_link, list);
	while (!list_empty(&bus->hlink_list)) {
		l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
		list_del(&l->list);
		kfree(l);
	}
@@ -144,7 +141,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
 * @ebus: HD-audio extended core bus
 * @codec_name: codec name
 */
struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,
struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
						 const char *codec_name)
{
	int i;
@@ -153,10 +150,10 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,

	if (sscanf(codec_name, "ehdaudio%dD%d", &bus_idx, &addr) != 2)
		return NULL;
	if (ebus->idx != bus_idx)
	if (bus->idx != bus_idx)
		return NULL;

	list_for_each_entry(hlink, &ebus->hlink_list, list) {
	list_for_each_entry(hlink, &bus->hlink_list, list) {
		for (i = 0; i < HDA_MAX_CODECS; i++) {
			if (hlink->lsdiid & (0x1 << addr))
				return hlink;
@@ -219,12 +216,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
 * snd_hdac_ext_bus_link_power_up_all -power up all hda link
 * @ebus: HD-audio extended bus
 */
int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
{
	struct hdac_ext_link *hlink = NULL;
	int ret;

	list_for_each_entry(hlink, &ebus->hlink_list, list) {
	list_for_each_entry(hlink, &bus->hlink_list, list) {
		snd_hdac_updatel(hlink->ml_addr,
				AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
		ret = check_hdac_link_power_active(hlink, true);
@@ -240,12 +237,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
 * snd_hdac_ext_bus_link_power_down_all -power down all hda link
 * @ebus: HD-audio extended bus
 */
int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
{
	struct hdac_ext_link *hlink = NULL;
	int ret;

	list_for_each_entry(hlink, &ebus->hlink_list, list) {
	list_for_each_entry(hlink, &bus->hlink_list, list) {
		snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
		ret = check_hdac_link_power_active(hlink, false);
		if (ret < 0)
@@ -256,39 +253,48 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);

int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
				struct hdac_ext_link *link)
{
	int ret = 0;

	mutex_lock(&ebus->lock);
	mutex_lock(&bus->lock);

	/*
	 * if we move from 0 to 1, count will be 1 so power up this link
	 * as well, also check the dma status and trigger that
	 */
	if (++link->ref_count == 1) {
		if (!ebus->cmd_dma_state) {
			snd_hdac_bus_init_cmd_io(&ebus->bus);
			ebus->cmd_dma_state = true;
		if (!bus->cmd_dma_state) {
			snd_hdac_bus_init_cmd_io(bus);
			bus->cmd_dma_state = true;
		}

		ret = snd_hdac_ext_bus_link_power_up(link);

		/*
		 *  wait for 521usec for codec to report status
		 *  HDA spec section 4.3 - Codec Discovery
		 */
		udelay(521);
		bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
		dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
		snd_hdac_chip_writew(bus, STATESTS, bus->codec_mask);
	}

	mutex_unlock(&ebus->lock);
	mutex_unlock(&bus->lock);
	return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);

int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
				struct hdac_ext_link *link)
{
	int ret = 0;
	struct hdac_ext_link *hlink;
	bool link_up = false;

	mutex_lock(&ebus->lock);
	mutex_lock(&bus->lock);

	/*
	 * if we move from 1 to 0, count will be 0
@@ -301,7 +307,7 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
		 * now check if all links are off, if so turn off
		 * cmd dma as well
		 */
		list_for_each_entry(hlink, &ebus->hlink_list, list) {
		list_for_each_entry(hlink, &bus->hlink_list, list) {
			if (hlink->ref_count) {
				link_up = true;
				break;
@@ -309,12 +315,12 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
		}

		if (!link_up) {
			snd_hdac_bus_stop_cmd_io(&ebus->bus);
			ebus->cmd_dma_state = false;
			snd_hdac_bus_stop_cmd_io(bus);
			bus->cmd_dma_state = false;
		}
	}

	mutex_unlock(&ebus->lock);
	mutex_unlock(&bus->lock);
	return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
+45 −59

File changed.

Preview size limit exceeded, changes collapsed.

Loading