Commit | Line | Data |
---|---|---|
5507b810 PLB |
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
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 | // | |
6 | // Copyright(c) 2018 Intel Corporation. All rights reserved. | |
7 | // | |
8 | // Authors: Keyon Jie <yang.jie@linux.intel.com> | |
9 | // | |
10 | ||
11 | #include <linux/module.h> | |
12 | #include <sound/hdaudio_ext.h> | |
fd15f2f5 | 13 | #include <sound/hda_register.h> |
5507b810 PLB |
14 | #include <sound/hda_codec.h> |
15 | #include <sound/hda_i915.h> | |
16 | #include <sound/sof.h> | |
17 | #include "../ops.h" | |
18 | #include "hda.h" | |
19 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) | |
20 | #include "../../codecs/hdac_hda.h" | |
21 | #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ | |
22 | ||
23 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) | |
24 | #define IDISP_VID_INTEL 0x80860000 | |
25 | ||
26 | /* load the legacy HDA codec driver */ | |
2c63bea7 | 27 | static int hda_codec_load_module(struct hda_codec *codec) |
5507b810 | 28 | { |
2c63bea7 | 29 | #ifdef MODULE |
5507b810 PLB |
30 | char alias[MODULE_NAME_LEN]; |
31 | const char *module = alias; | |
32 | ||
33 | snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias)); | |
34 | dev_dbg(&codec->core.dev, "loading codec module: %s\n", module); | |
35 | request_module(module); | |
5507b810 | 36 | #endif |
2c63bea7 KV |
37 | return device_attach(hda_codec_dev(codec)); |
38 | } | |
5507b810 | 39 | |
fd15f2f5 RW |
40 | /* enable controller wake up event for all codecs with jack connectors */ |
41 | void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) | |
42 | { | |
43 | struct hda_bus *hbus = sof_to_hbus(sdev); | |
44 | struct hdac_bus *bus = sof_to_bus(sdev); | |
45 | struct hda_codec *codec; | |
46 | unsigned int mask = 0; | |
47 | ||
48 | list_for_each_codec(codec, hbus) | |
49 | if (codec->jacktbl.used) | |
50 | mask |= BIT(codec->core.addr); | |
51 | ||
52 | snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); | |
53 | } | |
54 | ||
55 | /* check jack status after resuming from suspend mode */ | |
56 | void hda_codec_jack_check(struct snd_sof_dev *sdev) | |
57 | { | |
58 | struct hda_bus *hbus = sof_to_hbus(sdev); | |
59 | struct hdac_bus *bus = sof_to_bus(sdev); | |
60 | struct hda_codec *codec; | |
61 | ||
62 | /* disable controller Wake Up event*/ | |
63 | snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); | |
64 | ||
65 | list_for_each_codec(codec, hbus) | |
66 | /* | |
67 | * Wake up all jack-detecting codecs regardless whether an event | |
68 | * has been recorded in STATESTS | |
69 | */ | |
70 | if (codec->jacktbl.used) | |
71 | schedule_delayed_work(&codec->jackpoll_work, | |
72 | codec->jackpoll_interval); | |
73 | } | |
74 | #else | |
75 | void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) {} | |
76 | void hda_codec_jack_check(struct snd_sof_dev *sdev) {} | |
5507b810 | 77 | #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ |
5bd216c6 PLB |
78 | EXPORT_SYMBOL_NS(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC); |
79 | EXPORT_SYMBOL_NS(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC); | |
5507b810 PLB |
80 | |
81 | /* probe individual codec */ | |
80acdd4f RS |
82 | static int hda_codec_probe(struct snd_sof_dev *sdev, int address, |
83 | bool hda_codec_use_common_hdmi) | |
5507b810 | 84 | { |
5507b810 PLB |
85 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) |
86 | struct hdac_hda_priv *hda_priv; | |
87 | #endif | |
fd15f2f5 RW |
88 | struct hda_bus *hbus = sof_to_hbus(sdev); |
89 | struct hdac_device *hdev; | |
5507b810 PLB |
90 | u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | |
91 | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; | |
92 | u32 resp = -1; | |
93 | int ret; | |
94 | ||
95 | mutex_lock(&hbus->core.cmd_mutex); | |
96 | snd_hdac_bus_send_cmd(&hbus->core, hda_cmd); | |
97 | snd_hdac_bus_get_response(&hbus->core, address, &resp); | |
98 | mutex_unlock(&hbus->core.cmd_mutex); | |
99 | if (resp == -1) | |
100 | return -EIO; | |
101 | dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n", | |
102 | address, resp); | |
103 | ||
104 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) | |
ef9bec27 | 105 | hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL); |
5507b810 PLB |
106 | if (!hda_priv) |
107 | return -ENOMEM; | |
108 | ||
109 | hda_priv->codec.bus = hbus; | |
110 | hdev = &hda_priv->codec.core; | |
111 | ||
112 | ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev); | |
113 | if (ret < 0) | |
114 | return ret; | |
115 | ||
139c7feb KV |
116 | if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) |
117 | hda_priv->need_display_power = true; | |
118 | ||
119 | /* | |
120 | * if common HDMI codec driver is not used, codec load | |
121 | * is skipped here and hdac_hdmi is used instead | |
122 | */ | |
80acdd4f | 123 | if (hda_codec_use_common_hdmi || |
139c7feb | 124 | (resp & 0xFFFF0000) != IDISP_VID_INTEL) { |
5507b810 | 125 | hdev->type = HDA_DEV_LEGACY; |
2c63bea7 KV |
126 | ret = hda_codec_load_module(&hda_priv->codec); |
127 | /* | |
128 | * handle ret==0 (no driver bound) as an error, but pass | |
129 | * other return codes without modification | |
130 | */ | |
131 | if (ret == 0) | |
132 | ret = -ENOENT; | |
5507b810 PLB |
133 | } |
134 | ||
2c63bea7 | 135 | return ret; |
5507b810 | 136 | #else |
ef9bec27 | 137 | hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); |
5507b810 PLB |
138 | if (!hdev) |
139 | return -ENOMEM; | |
140 | ||
141 | ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev); | |
142 | ||
143 | return ret; | |
144 | #endif | |
145 | } | |
146 | ||
147 | /* Codec initialization */ | |
91dce767 KV |
148 | void hda_codec_probe_bus(struct snd_sof_dev *sdev, |
149 | bool hda_codec_use_common_hdmi) | |
5507b810 PLB |
150 | { |
151 | struct hdac_bus *bus = sof_to_bus(sdev); | |
152 | int i, ret; | |
153 | ||
154 | /* probe codecs in avail slots */ | |
155 | for (i = 0; i < HDA_MAX_CODECS; i++) { | |
156 | ||
157 | if (!(bus->codec_mask & (1 << i))) | |
158 | continue; | |
159 | ||
80acdd4f | 160 | ret = hda_codec_probe(sdev, i, hda_codec_use_common_hdmi); |
5507b810 | 161 | if (ret < 0) { |
91dce767 KV |
162 | dev_warn(bus->dev, "codec #%d probe error, ret: %d\n", |
163 | i, ret); | |
164 | bus->codec_mask &= ~BIT(i); | |
5507b810 PLB |
165 | } |
166 | } | |
5507b810 | 167 | } |
5bd216c6 | 168 | EXPORT_SYMBOL_NS(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC); |
5507b810 | 169 | |
139c7feb KV |
170 | #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ |
171 | IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) | |
5507b810 | 172 | |
23ee0903 | 173 | void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable) |
5507b810 PLB |
174 | { |
175 | struct hdac_bus *bus = sof_to_bus(sdev); | |
176 | ||
23ee0903 KV |
177 | dev_dbg(bus->dev, "Turning i915 HDAC power %d\n", enable); |
178 | snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable); | |
5507b810 | 179 | } |
23ee0903 | 180 | EXPORT_SYMBOL_NS(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); |
5507b810 PLB |
181 | |
182 | int hda_codec_i915_init(struct snd_sof_dev *sdev) | |
183 | { | |
184 | struct hdac_bus *bus = sof_to_bus(sdev); | |
185 | int ret; | |
186 | ||
187 | /* i915 exposes a HDA codec for HDMI audio */ | |
188 | ret = snd_hdac_i915_init(bus); | |
189 | if (ret < 0) | |
190 | return ret; | |
191 | ||
23ee0903 | 192 | hda_codec_i915_display_power(sdev, true); |
5507b810 PLB |
193 | |
194 | return 0; | |
195 | } | |
5bd216c6 | 196 | EXPORT_SYMBOL_NS(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); |
5507b810 PLB |
197 | |
198 | int hda_codec_i915_exit(struct snd_sof_dev *sdev) | |
199 | { | |
200 | struct hdac_bus *bus = sof_to_bus(sdev); | |
201 | int ret; | |
202 | ||
23ee0903 | 203 | hda_codec_i915_display_power(sdev, false); |
5507b810 PLB |
204 | |
205 | ret = snd_hdac_i915_exit(bus); | |
206 | ||
207 | return ret; | |
208 | } | |
5bd216c6 | 209 | EXPORT_SYMBOL_NS(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); |
5507b810 | 210 | |
139c7feb | 211 | #endif |
5507b810 PLB |
212 | |
213 | MODULE_LICENSE("Dual BSD/GPL"); |