Loading include/sound/hdaudio.h +29 −0 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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 */ Loading Loading @@ -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; Loading Loading @@ -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, Loading include/sound/hdaudio_ext.h +29 −94 Original line number Diff line number Diff line Loading @@ -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), \ Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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) \ Loading @@ -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 */ sound/hda/ext/hdac_ext_bus.c +35 −45 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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); } Loading @@ -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)); } /** Loading @@ -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); Loading @@ -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); sound/hda/ext/hdac_ext_controller.c +35 −29 Original line number Diff line number Diff line Loading @@ -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"); Loading @@ -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"); Loading @@ -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; Loading @@ -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; Loading @@ -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); } Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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) Loading @@ -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 Loading @@ -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; Loading @@ -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); Loading
include/sound/hdaudio.h +29 −0 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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 */ Loading Loading @@ -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; Loading Loading @@ -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, Loading
include/sound/hdaudio_ext.h +29 −94 Original line number Diff line number Diff line Loading @@ -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), \ Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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) \ Loading @@ -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 */
sound/hda/ext/hdac_ext_bus.c +35 −45 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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); Loading @@ -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) { Loading @@ -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); Loading @@ -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); } Loading @@ -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)); } /** Loading @@ -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); Loading @@ -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);
sound/hda/ext/hdac_ext_controller.c +35 −29 Original line number Diff line number Diff line Loading @@ -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"); Loading @@ -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"); Loading @@ -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; Loading @@ -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; Loading @@ -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); } Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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) Loading @@ -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 Loading @@ -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; Loading @@ -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);