xref: /linux/sound/hda/codecs/side-codecs/aw88399_hda.c (revision e5c91aac491def6ab3f90c4cc246e3fcb0f8f058)
1de7027c9SMarco Giunta // SPDX-License-Identifier: GPL-2.0-only
2de7027c9SMarco Giunta //
3de7027c9SMarco Giunta // AW88399 HDA side codec driver
4de7027c9SMarco Giunta //
5de7027c9SMarco Giunta // Based on cs35l41_hda.c and aw88399.c
6de7027c9SMarco Giunta //
7de7027c9SMarco Giunta 
8de7027c9SMarco Giunta #include <linux/acpi.h>
9de7027c9SMarco Giunta #include <linux/gpio/consumer.h>
10de7027c9SMarco Giunta #include <linux/i2c.h>
11de7027c9SMarco Giunta #include <linux/module.h>
12de7027c9SMarco Giunta #include <linux/mutex.h>
13de7027c9SMarco Giunta #include <linux/pm_runtime.h>
14de7027c9SMarco Giunta #include <linux/string.h>
15de7027c9SMarco Giunta #include <sound/hda_codec.h>
16de7027c9SMarco Giunta #include "../generic.h"
17de7027c9SMarco Giunta #include "hda_component.h"
18de7027c9SMarco Giunta #include "aw88399_hda.h"
19de7027c9SMarco Giunta 
20de7027c9SMarco Giunta #define AW88399_HDA_I2C_BASE_ADDR	0x34
21de7027c9SMarco Giunta 
22de7027c9SMarco Giunta static void aw88399_hda_playback_hook(struct device *dev, int action)
23de7027c9SMarco Giunta {
24de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
25de7027c9SMarco Giunta 	struct aw88399 *core = aw88399->core;
26de7027c9SMarco Giunta 	int ret = 0;
27de7027c9SMarco Giunta 
28de7027c9SMarco Giunta 	dev_dbg(aw88399->dev, "Playback action: %d\n", action);
29de7027c9SMarco Giunta 
30de7027c9SMarco Giunta 	switch (action) {
31de7027c9SMarco Giunta 	case HDA_GEN_PCM_ACT_OPEN:
32de7027c9SMarco Giunta 		pm_runtime_get_sync(dev);
33de7027c9SMarco Giunta 		aw88399->playing = true;
34de7027c9SMarco Giunta 		break;
35de7027c9SMarco Giunta 	case HDA_GEN_PCM_ACT_PREPARE:
36de7027c9SMarco Giunta 		if (core)
37de7027c9SMarco Giunta 			aw88399_start(core, AW88399_SYNC_START);
38de7027c9SMarco Giunta 		break;
39de7027c9SMarco Giunta 	case HDA_GEN_PCM_ACT_CLEANUP:
40de7027c9SMarco Giunta 		if (aw88399->aw_dev)
41de7027c9SMarco Giunta 			ret = aw88399_stop(aw88399->aw_dev);
42de7027c9SMarco Giunta 		if (ret)
43de7027c9SMarco Giunta 			dev_err(aw88399->dev, "Failed to stop amplifier: %d\n", ret);
44de7027c9SMarco Giunta 		break;
45de7027c9SMarco Giunta 	case HDA_GEN_PCM_ACT_CLOSE:
46de7027c9SMarco Giunta 		if (aw88399->aw_dev)
47de7027c9SMarco Giunta 			aw88399_stop(aw88399->aw_dev);
48de7027c9SMarco Giunta 		aw88399->playing = false;
49de7027c9SMarco Giunta 		pm_runtime_mark_last_busy(dev);
50de7027c9SMarco Giunta 		pm_runtime_put_autosuspend(dev);
51de7027c9SMarco Giunta 		break;
52de7027c9SMarco Giunta 	default:
53de7027c9SMarco Giunta 		dev_warn(aw88399->dev, "Unsupported action: %d\n", action);
54de7027c9SMarco Giunta 		break;
55de7027c9SMarco Giunta 	}
56de7027c9SMarco Giunta }
57de7027c9SMarco Giunta 
58de7027c9SMarco Giunta static int aw88399_hda_bind(struct device *dev, struct device *master, void *master_data)
59de7027c9SMarco Giunta {
60de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
61de7027c9SMarco Giunta 	struct hda_component_parent *parent = master_data;
62de7027c9SMarco Giunta 	struct hda_component *comp;
63de7027c9SMarco Giunta 
64de7027c9SMarco Giunta 	comp = hda_component_from_index(parent, aw88399->index);
65de7027c9SMarco Giunta 	if (!comp)
66de7027c9SMarco Giunta 		return -EINVAL;
67de7027c9SMarco Giunta 
68de7027c9SMarco Giunta 	if (comp->dev)
69de7027c9SMarco Giunta 		return -EBUSY;
70de7027c9SMarco Giunta 
71de7027c9SMarco Giunta 	comp->dev = dev;
72de7027c9SMarco Giunta 
73de7027c9SMarco Giunta 	strscpy(comp->name, dev_name(dev), sizeof(comp->name));
74de7027c9SMarco Giunta 
75de7027c9SMarco Giunta 	comp->playback_hook = aw88399_hda_playback_hook;
76de7027c9SMarco Giunta 
77de7027c9SMarco Giunta 	dev_info(aw88399->dev,
78de7027c9SMarco Giunta 		 "AW88399 Bound - SSID: %s, channel: %d\n",
79de7027c9SMarco Giunta 		 aw88399->acpi_subsystem_id, aw88399->channel);
80de7027c9SMarco Giunta 
81de7027c9SMarco Giunta 	return 0;
82de7027c9SMarco Giunta }
83de7027c9SMarco Giunta 
84de7027c9SMarco Giunta static void aw88399_hda_unbind(struct device *dev, struct device *master, void *master_data)
85de7027c9SMarco Giunta {
86de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
87de7027c9SMarco Giunta 	struct hda_component_parent *parent = master_data;
88de7027c9SMarco Giunta 	struct hda_component *comp;
89de7027c9SMarco Giunta 
90de7027c9SMarco Giunta 	comp = hda_component_from_index(parent, aw88399->index);
91de7027c9SMarco Giunta 	if (comp && (comp->dev == dev))
92de7027c9SMarco Giunta 		memset(comp, 0, sizeof(*comp));
93de7027c9SMarco Giunta 
94de7027c9SMarco Giunta 	dev_dbg(aw88399->dev, "Unbound from HDA codec\n");
95de7027c9SMarco Giunta }
96de7027c9SMarco Giunta 
97de7027c9SMarco Giunta static const struct component_ops aw88399_hda_comp_ops = {
98de7027c9SMarco Giunta 	.bind = aw88399_hda_bind,
99de7027c9SMarco Giunta 	.unbind = aw88399_hda_unbind,
100de7027c9SMarco Giunta };
101de7027c9SMarco Giunta 
102de7027c9SMarco Giunta static int aw88399_hda_index_from_i2c(struct aw88399_hda *aw88399)
103de7027c9SMarco Giunta {
104de7027c9SMarco Giunta 	return to_i2c_client(aw88399->dev)->addr - AW88399_HDA_I2C_BASE_ADDR;
105de7027c9SMarco Giunta }
106de7027c9SMarco Giunta 
107de7027c9SMarco Giunta static int aw88399_hda_init(struct aw88399_hda *aw88399)
108de7027c9SMarco Giunta {
109de7027c9SMarco Giunta 	struct device *dev = aw88399->dev;
110de7027c9SMarco Giunta 	struct i2c_client *i2c = to_i2c_client(dev);
111de7027c9SMarco Giunta 	struct aw88399 *core;
112de7027c9SMarco Giunta 	int ret;
113de7027c9SMarco Giunta 
114de7027c9SMarco Giunta 	core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
115de7027c9SMarco Giunta 	if (!core)
116de7027c9SMarco Giunta 		return -ENOMEM;
117de7027c9SMarco Giunta 
118de7027c9SMarco Giunta 	mutex_init(&core->lock);
119de7027c9SMarco Giunta 	core->reset_gpio = aw88399->reset_gpio;
120de7027c9SMarco Giunta 	core->regmap = aw88399->regmap;
121de7027c9SMarco Giunta 	core->bsts_unreliable = aw88399->bsts_unreliable;
122de7027c9SMarco Giunta 
123de7027c9SMarco Giunta 	aw88399_hw_reset(core);
124de7027c9SMarco Giunta 
125de7027c9SMarco Giunta 	ret = aw88399_init(core, i2c, aw88399->regmap);
126de7027c9SMarco Giunta 	if (ret)
127de7027c9SMarco Giunta 		return ret;
128de7027c9SMarco Giunta 
129de7027c9SMarco Giunta 	/* Set channel BEFORE loading firmware so ACF parser sees correct value */
130de7027c9SMarco Giunta 	if (core->aw_pa)
131de7027c9SMarco Giunta 		aw88399_dev_set_channel(core, aw88399->channel);
132de7027c9SMarco Giunta 
133de7027c9SMarco Giunta 	ret = aw88399_request_firmware_file(core);
134de7027c9SMarco Giunta 	if (ret)
135de7027c9SMarco Giunta 		return ret;
136de7027c9SMarco Giunta 
137de7027c9SMarco Giunta 	aw88399->core = core;
138de7027c9SMarco Giunta 	aw88399->aw_dev = core->aw_pa;
139de7027c9SMarco Giunta 
140de7027c9SMarco Giunta 	return 0;
141de7027c9SMarco Giunta }
142de7027c9SMarco Giunta 
143494978aeSMarco Giunta static int aw88399_swap_channels(struct aw88399_hda *aw88399)
144494978aeSMarco Giunta {
145494978aeSMarco Giunta 	/*
146494978aeSMarco Giunta 	 * Certain Lenovo Legion laptops have their
147494978aeSMarco Giunta 	 * I2C wiring reversed: 0x34 is physically the right speaker,
148494978aeSMarco Giunta 	 * 0x35 is the left. Swap channels to correct L/R assignment.
149494978aeSMarco Giunta 	 * This is a model-specific hardware wiring issue, not a driver bug.
150494978aeSMarco Giunta 	 */
151494978aeSMarco Giunta 	aw88399->channel = 1 - aw88399->channel;
152494978aeSMarco Giunta 	dev_dbg(aw88399->dev,
153494978aeSMarco Giunta 		"Channel swap applied: index %d -> channel %d\n",
154494978aeSMarco Giunta 		aw88399->index, aw88399->channel);
155494978aeSMarco Giunta 	return 0;
156494978aeSMarco Giunta }
157494978aeSMarco Giunta 
158494978aeSMarco Giunta static int aw88399_skip_bsts_check(struct aw88399_hda *aw88399)
159494978aeSMarco Giunta {
160494978aeSMarco Giunta 	/*
161494978aeSMarco Giunta 	 * BSTS (boost-finished) status bit does not reliably report on
162494978aeSMarco Giunta 	 * some hardware. On certain Lenovo Legion laptops, both amps
163494978aeSMarco Giunta 	 * report BSTS=0 (boost not finished) during normal playback
164494978aeSMarco Giunta 	 * despite clean audio output. Skip BSTS in the startup status
165494978aeSMarco Giunta 	 * check to avoid false init failures.
166494978aeSMarco Giunta 	 */
167494978aeSMarco Giunta 	aw88399->bsts_unreliable = true;
168494978aeSMarco Giunta 	dev_dbg(aw88399->dev, "BSTS status check disabled\n");
169494978aeSMarco Giunta 	return 0;
170494978aeSMarco Giunta }
171494978aeSMarco Giunta 
172494978aeSMarco Giunta static int aw88399_apply_legion_quirks(struct aw88399_hda *aw88399)
173494978aeSMarco Giunta {
174494978aeSMarco Giunta 	aw88399_swap_channels(aw88399);
175494978aeSMarco Giunta 	aw88399_skip_bsts_check(aw88399);
176494978aeSMarco Giunta 	return 0;
177494978aeSMarco Giunta }
178494978aeSMarco Giunta 
179de7027c9SMarco Giunta struct aw88399_prop_model {
180de7027c9SMarco Giunta 	const char *ssid;
181de7027c9SMarco Giunta 	int (*apply_prop)(struct aw88399_hda *aw88399);
182de7027c9SMarco Giunta };
183de7027c9SMarco Giunta 
184de7027c9SMarco Giunta static const struct aw88399_prop_model aw88399_prop_model_table[] = {
185494978aeSMarco Giunta 	{ "17AA3906", aw88399_apply_legion_quirks },
186494978aeSMarco Giunta 	{ "17AA3907", aw88399_apply_legion_quirks },
187494978aeSMarco Giunta 	{ "17AA3927", aw88399_apply_legion_quirks },
188494978aeSMarco Giunta 	{ "17AA3928", aw88399_apply_legion_quirks },
189*fde30db1SMarco Giunta 	{ "17AA3936", aw88399_apply_legion_quirks },
190*fde30db1SMarco Giunta 	{ "17AA3937", aw88399_apply_legion_quirks },
191494978aeSMarco Giunta 	{ "17AA3938", aw88399_apply_legion_quirks },
192494978aeSMarco Giunta 	{ "17AA3939", aw88399_apply_legion_quirks },
193de7027c9SMarco Giunta 	{ }
194de7027c9SMarco Giunta };
195de7027c9SMarco Giunta 
196de7027c9SMarco Giunta static int aw88399_hda_acpi_probe(struct aw88399_hda *aw88399)
197de7027c9SMarco Giunta {
198de7027c9SMarco Giunta 	struct acpi_device *adev;
199de7027c9SMarco Giunta 	const char *sub;
200de7027c9SMarco Giunta 	const struct aw88399_prop_model *model;
201de7027c9SMarco Giunta 
202de7027c9SMarco Giunta 	aw88399->index = aw88399_hda_index_from_i2c(aw88399);
203de7027c9SMarco Giunta 	aw88399->channel = aw88399->index;
204de7027c9SMarco Giunta 	aw88399->acpi_subsystem_id = NULL;
205de7027c9SMarco Giunta 
206de7027c9SMarco Giunta 	adev = acpi_dev_get_first_match_dev("AWDZ8399", NULL, -1);
207de7027c9SMarco Giunta 	if (!adev) {
208de7027c9SMarco Giunta 		dev_err(aw88399->dev, "Failed to find an ACPI device for AWDZ8399\n");
209de7027c9SMarco Giunta 		return -ENODEV;
210de7027c9SMarco Giunta 	}
211de7027c9SMarco Giunta 
2125713fea9STakashi Iwai 	struct device *physdev __free(put_device) =
2135713fea9STakashi Iwai 		get_device(acpi_get_first_physical_node(adev));
214de7027c9SMarco Giunta 	acpi_dev_put(adev);
215de7027c9SMarco Giunta 	if (!physdev)
216de7027c9SMarco Giunta 		return -ENODEV;
217de7027c9SMarco Giunta 
218de7027c9SMarco Giunta 	sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
219de7027c9SMarco Giunta 	if (IS_ERR_OR_NULL(sub))
220de7027c9SMarco Giunta 		return 0;
221de7027c9SMarco Giunta 
222de7027c9SMarco Giunta 	aw88399->acpi_subsystem_id = devm_kstrdup(aw88399->dev, sub, GFP_KERNEL);
223de7027c9SMarco Giunta 	kfree(sub);
224de7027c9SMarco Giunta 	if (!aw88399->acpi_subsystem_id)
225de7027c9SMarco Giunta 		return -ENOMEM;
226de7027c9SMarco Giunta 
227de7027c9SMarco Giunta 	for (model = aw88399_prop_model_table; model->ssid; model++) {
228de7027c9SMarco Giunta 		if (!strcasecmp(model->ssid, aw88399->acpi_subsystem_id)) {
229de7027c9SMarco Giunta 			dev_info(aw88399->dev,
230de7027c9SMarco Giunta 				 "Applying properties for SSID %s\n",
231de7027c9SMarco Giunta 				 aw88399->acpi_subsystem_id);
232de7027c9SMarco Giunta 			return model->apply_prop(aw88399);
233de7027c9SMarco Giunta 		}
234de7027c9SMarco Giunta 	}
235de7027c9SMarco Giunta 
236de7027c9SMarco Giunta 	return 0;
237de7027c9SMarco Giunta }
238de7027c9SMarco Giunta 
239de7027c9SMarco Giunta int aw88399_hda_probe(struct device *dev, struct regmap *regmap)
240de7027c9SMarco Giunta {
241de7027c9SMarco Giunta 	struct aw88399_hda *aw88399;
242de7027c9SMarco Giunta 	int ret;
243de7027c9SMarco Giunta 
244de7027c9SMarco Giunta 	aw88399 = devm_kzalloc(dev, sizeof(*aw88399), GFP_KERNEL);
245de7027c9SMarco Giunta 	if (!aw88399)
246de7027c9SMarco Giunta 		return -ENOMEM;
247de7027c9SMarco Giunta 
248de7027c9SMarco Giunta 	if (IS_ERR(regmap))
249de7027c9SMarco Giunta 		return dev_err_probe(dev, PTR_ERR(regmap), "Failed to obtain regmap\n");
250de7027c9SMarco Giunta 
251de7027c9SMarco Giunta 	aw88399->dev = dev;
252de7027c9SMarco Giunta 	aw88399->regmap = regmap;
253de7027c9SMarco Giunta 	dev_set_drvdata(dev, aw88399);
254de7027c9SMarco Giunta 
255de7027c9SMarco Giunta 	aw88399->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
256de7027c9SMarco Giunta 	if (IS_ERR(aw88399->reset_gpio))
257de7027c9SMarco Giunta 		return dev_err_probe(dev, PTR_ERR(aw88399->reset_gpio),
258de7027c9SMarco Giunta 				     "Failed to get reset GPIO\n");
259de7027c9SMarco Giunta 
260de7027c9SMarco Giunta 	ret = aw88399_hda_acpi_probe(aw88399);
261de7027c9SMarco Giunta 	if (ret)
262de7027c9SMarco Giunta 		return dev_err_probe(dev, ret, "ACPI probe failed\n");
263de7027c9SMarco Giunta 
264de7027c9SMarco Giunta 	ret = aw88399_hda_init(aw88399);
265de7027c9SMarco Giunta 	if (ret)
266de7027c9SMarco Giunta 		return dev_err_probe(dev, ret, "Chip initialization failed\n");
267de7027c9SMarco Giunta 
268de7027c9SMarco Giunta 	/* Enable runtime PM */
269de7027c9SMarco Giunta 	pm_runtime_set_autosuspend_delay(dev, 3000);
270de7027c9SMarco Giunta 	pm_runtime_use_autosuspend(dev);
271de7027c9SMarco Giunta 	pm_runtime_mark_last_busy(dev);
272de7027c9SMarco Giunta 	pm_runtime_set_active(dev);
273de7027c9SMarco Giunta 	pm_runtime_enable(dev);
274de7027c9SMarco Giunta 
275de7027c9SMarco Giunta 	ret = component_add(dev, &aw88399_hda_comp_ops);
276de7027c9SMarco Giunta 	if (ret) {
277de7027c9SMarco Giunta 		pm_runtime_disable(dev);
278de7027c9SMarco Giunta 		return dev_err_probe(dev, ret, "Failed to register component\n");
279de7027c9SMarco Giunta 	}
280de7027c9SMarco Giunta 
281de7027c9SMarco Giunta 	dev_info(dev, "AW88399 HDA side codec registered successfully\n");
282de7027c9SMarco Giunta 
283de7027c9SMarco Giunta 	return 0;
284de7027c9SMarco Giunta }
285de7027c9SMarco Giunta EXPORT_SYMBOL_NS_GPL(aw88399_hda_probe, "SND_HDA_SCODEC_AW88399");
286de7027c9SMarco Giunta 
287de7027c9SMarco Giunta void aw88399_hda_remove(struct device *dev)
288de7027c9SMarco Giunta {
289de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
290de7027c9SMarco Giunta 
291de7027c9SMarco Giunta 	pm_runtime_disable(dev);
292de7027c9SMarco Giunta 
293de7027c9SMarco Giunta 	if (aw88399->aw_dev)
294de7027c9SMarco Giunta 		aw88399_stop(aw88399->aw_dev);
295de7027c9SMarco Giunta 
296de7027c9SMarco Giunta 	component_del(dev, &aw88399_hda_comp_ops);
297de7027c9SMarco Giunta 
298de7027c9SMarco Giunta 	dev_dbg(aw88399->dev, "AW88399 HDA side codec removed\n");
299de7027c9SMarco Giunta }
300de7027c9SMarco Giunta EXPORT_SYMBOL_NS_GPL(aw88399_hda_remove, "SND_HDA_SCODEC_AW88399");
301de7027c9SMarco Giunta 
302de7027c9SMarco Giunta static int aw88399_hda_runtime_suspend(struct device *dev)
303de7027c9SMarco Giunta {
304de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
305de7027c9SMarco Giunta 
306de7027c9SMarco Giunta 	dev_dbg(aw88399->dev, "Runtime suspend\n");
307de7027c9SMarco Giunta 
308de7027c9SMarco Giunta 	if (aw88399->aw_dev && aw88399->playing)
309de7027c9SMarco Giunta 		aw88399_stop(aw88399->aw_dev);
310de7027c9SMarco Giunta 
311de7027c9SMarco Giunta 	return 0;
312de7027c9SMarco Giunta }
313de7027c9SMarco Giunta 
314de7027c9SMarco Giunta static int aw88399_hda_runtime_resume(struct device *dev)
315de7027c9SMarco Giunta {
316de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
317de7027c9SMarco Giunta 
318de7027c9SMarco Giunta 	dev_dbg(aw88399->dev, "Runtime resume\n");
319de7027c9SMarco Giunta 
320de7027c9SMarco Giunta 	if (aw88399->core && aw88399->aw_dev && aw88399->playing)
321de7027c9SMarco Giunta 		aw88399_start(aw88399->core, AW88399_SYNC_START);
322de7027c9SMarco Giunta 
323de7027c9SMarco Giunta 	return 0;
324de7027c9SMarco Giunta }
325de7027c9SMarco Giunta 
326de7027c9SMarco Giunta static int aw88399_hda_system_suspend(struct device *dev)
327de7027c9SMarco Giunta {
328de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
329de7027c9SMarco Giunta 	int ret;
330de7027c9SMarco Giunta 
331de7027c9SMarco Giunta 	dev_dbg(aw88399->dev, "System suspend\n");
332de7027c9SMarco Giunta 
333de7027c9SMarco Giunta 	if (aw88399->aw_dev && aw88399->playing)
334de7027c9SMarco Giunta 		aw88399_stop(aw88399->aw_dev);
335de7027c9SMarco Giunta 
336de7027c9SMarco Giunta 	if (aw88399->core)
337de7027c9SMarco Giunta 		aw88399->core->fw_needs_reload = true;
338de7027c9SMarco Giunta 
339de7027c9SMarco Giunta 	ret = pm_runtime_force_suspend(dev);
340de7027c9SMarco Giunta 	if (ret)
341de7027c9SMarco Giunta 		dev_err(aw88399->dev, "Runtime force suspend failed: %d\n", ret);
342de7027c9SMarco Giunta 
343de7027c9SMarco Giunta 	return ret;
344de7027c9SMarco Giunta }
345de7027c9SMarco Giunta 
346de7027c9SMarco Giunta static int aw88399_hda_system_resume(struct device *dev)
347de7027c9SMarco Giunta {
348de7027c9SMarco Giunta 	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
349de7027c9SMarco Giunta 	int ret;
350de7027c9SMarco Giunta 
351de7027c9SMarco Giunta 	dev_dbg(aw88399->dev, "System resume\n");
352de7027c9SMarco Giunta 
353de7027c9SMarco Giunta 	if (aw88399->aw_dev)
354de7027c9SMarco Giunta 		aw88399_hw_reset(aw88399->core);
355de7027c9SMarco Giunta 
356de7027c9SMarco Giunta 	ret = pm_runtime_force_resume(dev);
357de7027c9SMarco Giunta 	if (ret)
358de7027c9SMarco Giunta 		dev_err(aw88399->dev, "Runtime force resume failed: %d\n", ret);
359de7027c9SMarco Giunta 
360de7027c9SMarco Giunta 	return ret;
361de7027c9SMarco Giunta }
362de7027c9SMarco Giunta 
363de7027c9SMarco Giunta const struct dev_pm_ops aw88399_hda_pm_ops = {
364de7027c9SMarco Giunta 	RUNTIME_PM_OPS(aw88399_hda_runtime_suspend, aw88399_hda_runtime_resume, NULL)
365de7027c9SMarco Giunta 	SYSTEM_SLEEP_PM_OPS(aw88399_hda_system_suspend, aw88399_hda_system_resume)
366de7027c9SMarco Giunta };
367de7027c9SMarco Giunta EXPORT_SYMBOL_NS_GPL(aw88399_hda_pm_ops, "SND_HDA_SCODEC_AW88399");
368de7027c9SMarco Giunta 
369de7027c9SMarco Giunta MODULE_DESCRIPTION("AW88399 HDA driver");
370de7027c9SMarco Giunta MODULE_AUTHOR("Yakov Till <yakov.till@gmail.com>");
371de7027c9SMarco Giunta MODULE_AUTHOR("Marco Giunta <marco_giunta@outlook.it>");
372de7027c9SMarco Giunta MODULE_LICENSE("GPL");
373de7027c9SMarco Giunta MODULE_FIRMWARE("aw88399_acf.bin");
374