1 /*
2  * Copyright (c) 2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <zephyr/spinlock.h>
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/pm/device.h>
14 #include <zephyr/pm/device_runtime.h>
15 #include <zephyr/logging/log.h>
16 
17 #define DT_DRV_COMPAT intel_hda_dai
18 #define LOG_DOMAIN dai_intel_hda
19 
20 LOG_MODULE_REGISTER(LOG_DOMAIN);
21 
22 #include "hda.h"
23 
dai_hda_trigger(const struct device * dev,enum dai_dir dir,enum dai_trigger_cmd cmd)24 static int dai_hda_trigger(const struct device *dev, enum dai_dir dir,
25 			   enum dai_trigger_cmd cmd)
26 {
27 	LOG_DBG("cmd %d", cmd);
28 
29 	return 0;
30 }
31 
32 /* Digital Audio interface formatting */
dai_hda_set_config_tplg(struct dai_intel_hda * dp,const void * spec_config)33 static int dai_hda_set_config_tplg(struct dai_intel_hda *dp, const void *spec_config)
34 {
35 	struct dai_intel_hda_pdata *hda = dai_get_drvdata(dp);
36 	const struct dai_intel_ipc_hda_params *config = spec_config;
37 
38 	if (config->channels) {
39 		hda->params.channels = config->channels;
40 	}
41 
42 	if (config->rate) {
43 		hda->params.rate = config->rate;
44 	}
45 
46 	return 0;
47 }
48 
dai_hda_config_get(const struct device * dev,struct dai_config * cfg,enum dai_dir dir)49 static int dai_hda_config_get(const struct device *dev, struct dai_config *cfg, enum dai_dir dir)
50 {
51 	struct dai_config *params = (struct dai_config *)dev->config;
52 	struct dai_intel_hda *dp = (struct dai_intel_hda *)dev->data;
53 	struct dai_intel_hda_pdata *hda = dai_get_drvdata(dp);
54 
55 	if (!cfg) {
56 		return -EINVAL;
57 	}
58 
59 	params->rate = hda->params.rate;
60 	params->channels = hda->params.channels;
61 
62 	params->word_size = DAI_INTEL_HDA_DEFAULT_WORD_SIZE;
63 
64 	*cfg = *params;
65 
66 	return 0;
67 }
68 
dai_hda_config_set(const struct device * dev,const struct dai_config * cfg,const void * bespoke_cfg)69 static int dai_hda_config_set(const struct device *dev, const struct dai_config *cfg,
70 				  const void *bespoke_cfg)
71 {
72 	struct dai_intel_hda *dp = (struct dai_intel_hda *)dev->data;
73 
74 	if (cfg->type == DAI_INTEL_HDA) {
75 		return dai_hda_set_config_tplg(dp, bespoke_cfg);
76 	}
77 
78 	return 0;
79 }
80 
dai_hda_get_properties(const struct device * dev,enum dai_dir dir,int stream_id)81 static const struct dai_properties *dai_hda_get_properties(const struct device *dev,
82 							   enum dai_dir dir, int stream_id)
83 {
84 	struct dai_intel_hda *dp = (struct dai_intel_hda *)dev->data;
85 	struct dai_intel_hda_pdata *hda = dai_get_drvdata(dp);
86 	struct dai_properties *prop = &hda->props;
87 
88 	prop->fifo_address = 0;
89 	prop->dma_hs_id = 0;
90 	prop->stream_id = 0;
91 
92 	return prop;
93 }
94 
dai_hda_probe(const struct device * dev)95 static int dai_hda_probe(const struct device *dev)
96 {
97 	LOG_DBG("%s", __func__);
98 
99 	return 0;
100 }
101 
dai_hda_remove(const struct device * dev)102 static int dai_hda_remove(const struct device *dev)
103 {
104 	LOG_DBG("%s", __func__);
105 
106 	return 0;
107 }
108 
hda_pm_action(const struct device * dev,enum pm_device_action action)109 static int hda_pm_action(const struct device *dev, enum pm_device_action action)
110 {
111 	switch (action) {
112 	case PM_DEVICE_ACTION_SUSPEND:
113 		dai_hda_remove(dev);
114 		break;
115 	case PM_DEVICE_ACTION_RESUME:
116 		dai_hda_probe(dev);
117 		break;
118 	case PM_DEVICE_ACTION_TURN_OFF:
119 	case PM_DEVICE_ACTION_TURN_ON:
120 		/* All device pm is handled during resume and suspend */
121 		break;
122 	default:
123 		return -ENOTSUP;
124 	}
125 
126 	return 0;
127 }
128 
hda_init(const struct device * dev)129 static int hda_init(const struct device *dev)
130 {
131 	LOG_DBG("%s", __func__);
132 	return pm_device_driver_init(dev, hda_pm_action);
133 }
134 
135 static DEVICE_API(dai, dai_intel_hda_api_funcs) = {
136 	.probe			= pm_device_runtime_get,
137 	.remove			= pm_device_runtime_put,
138 	.config_set		= dai_hda_config_set,
139 	.config_get		= dai_hda_config_get,
140 	.trigger		= dai_hda_trigger,
141 	.get_properties		= dai_hda_get_properties,
142 };
143 
144 #define DAI_INTEL_HDA_DEVICE_INIT(n)				\
145 	static struct dai_config dai_intel_hda_config_##n = {	\
146 		.type = DAI_INTEL_HDA,				\
147 		.dai_index = DT_INST_REG_ADDR(n),	\
148 	};							\
149 	static struct dai_intel_hda dai_intel_hda_data_##n = {	\
150 		.index = DT_INST_REG_ADDR(n)		\
151 								\
152 	};							\
153 								\
154 	PM_DEVICE_DT_INST_DEFINE(n, hda_pm_action);		\
155 								\
156 	DEVICE_DT_INST_DEFINE(n,				\
157 			hda_init, PM_DEVICE_DT_INST_GET(n),	\
158 			&dai_intel_hda_data_##n,		\
159 			&dai_intel_hda_config_##n,		\
160 			POST_KERNEL,				\
161 			CONFIG_DAI_INIT_PRIORITY,		\
162 			&dai_intel_hda_api_funcs);
163 
164 DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_HDA_DEVICE_INIT)
165