Commit | Line | Data |
---|---|---|
e149ca29 | 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
78ad1f07 KJ |
2 | // |
3 | // This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | // redistributing this file, you may do so under either license. | |
5 | // | |
293ad281 | 6 | // Copyright(c) 2018 Intel Corporation |
78ad1f07 KJ |
7 | // |
8 | // Authors: Keyon Jie <yang.jie@linux.intel.com> | |
9 | ||
10 | #include <linux/io.h> | |
11 | #include <sound/hdaudio.h> | |
c99fafdf | 12 | #include <sound/hda_i915.h> |
fd572393 KV |
13 | #include <sound/hda_codec.h> |
14 | #include <sound/hda_register.h> | |
78ad1f07 KJ |
15 | #include "../sof-priv.h" |
16 | #include "hda.h" | |
17 | ||
d4ff1b39 | 18 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) |
40073a9d | 19 | #include "../../codecs/hdac_hda.h" |
d4ff1b39 | 20 | #define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() |
78ad1f07 | 21 | |
fd572393 KV |
22 | static void update_codec_wake_enable(struct hdac_bus *bus, unsigned int addr, bool link_power) |
23 | { | |
24 | unsigned int mask = snd_hdac_chip_readw(bus, WAKEEN); | |
25 | ||
26 | if (link_power) | |
27 | mask &= ~BIT(addr); | |
28 | else | |
29 | mask |= BIT(addr); | |
30 | ||
31 | snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); | |
32 | } | |
33 | ||
c99fafdf KV |
34 | static void sof_hda_bus_link_power(struct hdac_device *codec, bool enable) |
35 | { | |
36 | struct hdac_bus *bus = codec->bus; | |
37 | bool oldstate = test_bit(codec->addr, &bus->codec_powered); | |
38 | ||
39 | snd_hdac_ext_bus_link_power(codec, enable); | |
40 | ||
41 | if (enable == oldstate) | |
42 | return; | |
43 | ||
44 | /* | |
45 | * Both codec driver and controller can hold references to | |
46 | * display power. To avoid unnecessary power-up/down cycles, | |
47 | * controller doesn't immediately release its reference. | |
48 | * | |
49 | * If the codec driver powers down the link, release | |
50 | * the controller reference as well. | |
51 | */ | |
52 | if (codec->addr == HDA_IDISP_ADDR && !enable) | |
53 | snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); | |
fd572393 KV |
54 | |
55 | /* WAKEEN needs to be set for disabled links */ | |
56 | update_codec_wake_enable(bus, codec->addr, enable); | |
c99fafdf KV |
57 | } |
58 | ||
87fc20e4 KV |
59 | static const struct hdac_bus_ops bus_core_ops = { |
60 | .command = snd_hdac_bus_send_cmd, | |
61 | .get_response = snd_hdac_bus_get_response, | |
c99fafdf | 62 | .link_power = sof_hda_bus_link_power, |
87fc20e4 KV |
63 | }; |
64 | #endif | |
65 | ||
78ad1f07 KJ |
66 | /* |
67 | * This can be used for both with/without hda link support. | |
68 | */ | |
afae0942 | 69 | void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) |
78ad1f07 | 70 | { |
afae0942 PLB |
71 | struct hdac_bus *bus = sof_to_bus(sdev); |
72 | ||
fb0bdfe2 | 73 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) |
afae0942 | 74 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) |
87fc20e4 | 75 | snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops); |
fb0bdfe2 PLB |
76 | #else |
77 | snd_hdac_ext_bus_init(bus, dev, NULL, NULL); | |
78 | #endif | |
79 | #else | |
80 | ||
78ad1f07 KJ |
81 | memset(bus, 0, sizeof(*bus)); |
82 | bus->dev = dev; | |
83 | ||
78ad1f07 KJ |
84 | INIT_LIST_HEAD(&bus->stream_list); |
85 | ||
86 | bus->irq = -1; | |
d1a6459f ZY |
87 | |
88 | /* | |
89 | * There is only one HDA bus atm. keep the index as 0. | |
90 | * Need to fix when there are more than one HDA bus. | |
91 | */ | |
92 | bus->idx = 0; | |
78ad1f07 KJ |
93 | |
94 | spin_lock_init(&bus->reg_lock); | |
fb0bdfe2 | 95 | #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ |
afae0942 PLB |
96 | } |
97 | ||
98 | void sof_hda_bus_exit(struct snd_sof_dev *sdev) | |
99 | { | |
fb0bdfe2 | 100 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) |
afae0942 PLB |
101 | struct hdac_bus *bus = sof_to_bus(sdev); |
102 | ||
103 | snd_hdac_ext_bus_exit(bus); | |
104 | #endif | |
78ad1f07 | 105 | } |