Skip to content

Commit d210dfd

Browse files
kv2019iCommit Bot
authored andcommitted
FROMGIT: ALSA: hda: add link_power op to hdac_bus_ops
The extended HDA bus (hdac_ext) provides interfaces for more fine-grained control of individual links than what plain HDA provides for. Links can be powered off when they are not used and if all links are released, controller can shut down the command DMA. These interfaces are currently not used by common HDA codec drivers. When a HDA codec is runtime suspended, it calls snd_hdac_codec_link_down(), but there is no link to the HDA extended bus, and on controller side the links are shut down only when all codecs are suspended. This patch adds link_power() to hdac_bus ops. Controllers using the HDA extended core, can use this to plug in snd_hdac_ext_bus_link_power() to implement more fine-grained control of link power. No change is needed for plain HDA controllers nor to existing HDA codec drivers. Co-developed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Signed-off-by: Chintan Patel <chintan.m.patel@intel.com> (cherry picked from commit f9e5fd1 https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git for-next) BUG=b:176942010 TEST=Enabling Google Assistant meets Power KPI Change-Id: I7c0a1f21b5923e1dae7a772209f955a940d5abe2 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2679469 Reviewed-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Curtis Malainey <cujomalainey@chromium.org> Tested-by: Jairaj Arava <jairaj.arava@intel.corp-partner.google.com> Commit-Queue: Curtis Malainey <cujomalainey@chromium.org>
1 parent 81b520f commit d210dfd

5 files changed

Lines changed: 81 additions & 9 deletions

File tree

include/sound/hdaudio.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ struct hdac_bus_ops {
241241
/* get a response from the last command */
242242
int (*get_response)(struct hdac_bus *bus, unsigned int addr,
243243
unsigned int *res);
244+
/* notify of codec link power-up/down */
245+
void (*link_power)(struct hdac_device *hdev, bool enable);
244246
};
245247

246248
/*
@@ -379,15 +381,8 @@ int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
379381
unsigned int cmd, unsigned int *res);
380382
void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
381383

382-
static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
383-
{
384-
set_bit(codec->addr, &codec->bus->codec_powered);
385-
}
386-
387-
static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
388-
{
389-
clear_bit(codec->addr, &codec->bus->codec_powered);
390-
}
384+
void snd_hdac_codec_link_up(struct hdac_device *codec);
385+
void snd_hdac_codec_link_down(struct hdac_device *codec);
391386

392387
int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
393388
int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
@@ -401,6 +396,7 @@ void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus);
401396
void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus);
402397
void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus);
403398
int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset);
399+
void snd_hdac_bus_link_power(struct hdac_device *hdev, bool enable);
404400

405401
void snd_hdac_bus_update_rirb(struct hdac_bus *bus);
406402
int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,

include/sound/hdaudio_ext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
131131
int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link);
132132
int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link);
133133

134+
void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable);
135+
134136
/* update register macro */
135137
#define snd_hdac_updatel(addr, reg, mask, val) \
136138
writel(((readl(addr + reg) & ~(mask)) | (val)), \

sound/hda/ext/hdac_ext_controller.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,40 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
332332
return ret;
333333
}
334334
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
335+
336+
static void hdac_ext_codec_link_up(struct hdac_device *codec)
337+
{
338+
const char *devname = dev_name(&codec->dev);
339+
struct hdac_ext_link *hlink =
340+
snd_hdac_ext_bus_get_link(codec->bus, devname);
341+
342+
if (hlink)
343+
snd_hdac_ext_bus_link_get(codec->bus, hlink);
344+
}
345+
346+
static void hdac_ext_codec_link_down(struct hdac_device *codec)
347+
{
348+
const char *devname = dev_name(&codec->dev);
349+
struct hdac_ext_link *hlink =
350+
snd_hdac_ext_bus_get_link(codec->bus, devname);
351+
352+
if (hlink)
353+
snd_hdac_ext_bus_link_put(codec->bus, hlink);
354+
}
355+
356+
void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable)
357+
{
358+
struct hdac_bus *bus = codec->bus;
359+
bool oldstate = test_bit(codec->addr, &bus->codec_powered);
360+
361+
if (enable == oldstate)
362+
return;
363+
364+
snd_hdac_bus_link_power(codec, enable);
365+
366+
if (enable)
367+
hdac_ext_codec_link_up(codec);
368+
else
369+
hdac_ext_codec_link_down(codec);
370+
}
371+
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power);

sound/hda/hdac_bus.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ static void snd_hdac_bus_process_unsol_events(struct work_struct *work);
1717
static const struct hdac_bus_ops default_ops = {
1818
.command = snd_hdac_bus_send_cmd,
1919
.get_response = snd_hdac_bus_get_response,
20+
.link_power = snd_hdac_bus_link_power,
2021
};
2122

2223
/**
@@ -262,3 +263,25 @@ void snd_hdac_aligned_write(unsigned int val, void __iomem *addr,
262263
}
263264
EXPORT_SYMBOL_GPL(snd_hdac_aligned_write);
264265
#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */
266+
267+
void snd_hdac_codec_link_up(struct hdac_device *codec)
268+
{
269+
struct hdac_bus *bus = codec->bus;
270+
271+
if (bus->ops->link_power)
272+
bus->ops->link_power(codec, true);
273+
else
274+
snd_hdac_bus_link_power(codec, true);
275+
}
276+
EXPORT_SYMBOL_GPL(snd_hdac_codec_link_up);
277+
278+
void snd_hdac_codec_link_down(struct hdac_device *codec)
279+
{
280+
struct hdac_bus *bus = codec->bus;
281+
282+
if (bus->ops->link_power)
283+
bus->ops->link_power(codec, false);
284+
else
285+
snd_hdac_bus_link_power(codec, false);
286+
}
287+
EXPORT_SYMBOL_GPL(snd_hdac_codec_link_down);

sound/hda/hdac_controller.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,3 +622,17 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus)
622622
snd_dma_free_pages(&bus->posbuf);
623623
}
624624
EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages);
625+
626+
/**
627+
* snd_hdac_bus_link_power - power up/down codec link
628+
* @codec: HD-audio device
629+
* @enable: whether to power-up the link
630+
*/
631+
void snd_hdac_bus_link_power(struct hdac_device *codec, bool enable)
632+
{
633+
if (enable)
634+
set_bit(codec->addr, &codec->bus->codec_powered);
635+
else
636+
clear_bit(codec->addr, &codec->bus->codec_powered);
637+
}
638+
EXPORT_SYMBOL_GPL(snd_hdac_bus_link_power);

0 commit comments

Comments
 (0)