1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Greybus Audio Device Class Protocol helpers
4  *
5  * Copyright 2015-2016 Google Inc.
6  */
7 
8 #include "greybus.h"
9 #include "greybus_protocols.h"
10 #include "audio_apbridgea.h"
11 #include "audio_codec.h"
12 
13 int gb_audio_apbridgea_set_config(struct gb_connection *connection,
14 				  __u16 i2s_port, __u32 format, __u32 rate,
15 				  __u32 mclk_freq)
16 {
17 	struct audio_apbridgea_set_config_request req;
18 
19 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_CONFIG;
20 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
21 	req.format = cpu_to_le32(format);
22 	req.rate = cpu_to_le32(rate);
23 	req.mclk_freq = cpu_to_le32(mclk_freq);
24 
25 	return gb_hd_output(connection->hd, &req, sizeof(req),
26 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
27 }
28 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_config);
29 
30 int gb_audio_apbridgea_register_cport(struct gb_connection *connection,
31 				      __u16 i2s_port, __u16 cportid,
32 				      __u8 direction)
33 {
34 	struct audio_apbridgea_register_cport_request req;
35 	int ret;
36 
37 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_REGISTER_CPORT;
38 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
39 	req.cport = cpu_to_le16(cportid);
40 	req.direction = direction;
41 
42 	ret = gb_pm_runtime_get_sync(connection->bundle);
43 	if (ret)
44 		return ret;
45 
46 	return gb_hd_output(connection->hd, &req, sizeof(req),
47 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
48 }
49 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_register_cport);
50 
51 int gb_audio_apbridgea_unregister_cport(struct gb_connection *connection,
52 					__u16 i2s_port, __u16 cportid,
53 					__u8 direction)
54 {
55 	struct audio_apbridgea_unregister_cport_request req;
56 	int ret;
57 
58 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_UNREGISTER_CPORT;
59 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
60 	req.cport = cpu_to_le16(cportid);
61 	req.direction = direction;
62 
63 	ret = gb_hd_output(connection->hd, &req, sizeof(req),
64 			   GB_APB_REQUEST_AUDIO_CONTROL, true);
65 
66 	gb_pm_runtime_put_autosuspend(connection->bundle);
67 
68 	return ret;
69 }
70 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_unregister_cport);
71 
72 int gb_audio_apbridgea_set_tx_data_size(struct gb_connection *connection,
73 					__u16 i2s_port, __u16 size)
74 {
75 	struct audio_apbridgea_set_tx_data_size_request req;
76 
77 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_TX_DATA_SIZE;
78 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
79 	req.size = cpu_to_le16(size);
80 
81 	return gb_hd_output(connection->hd, &req, sizeof(req),
82 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
83 }
84 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_tx_data_size);
85 
86 int gb_audio_apbridgea_prepare_tx(struct gb_connection *connection,
87 				  __u16 i2s_port)
88 {
89 	struct audio_apbridgea_prepare_tx_request req;
90 
91 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_PREPARE_TX;
92 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
93 
94 	return gb_hd_output(connection->hd, &req, sizeof(req),
95 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
96 }
97 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_prepare_tx);
98 
99 int gb_audio_apbridgea_start_tx(struct gb_connection *connection,
100 				__u16 i2s_port, __u64 timestamp)
101 {
102 	struct audio_apbridgea_start_tx_request req;
103 
104 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_START_TX;
105 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
106 	req.timestamp = cpu_to_le64(timestamp);
107 
108 	return gb_hd_output(connection->hd, &req, sizeof(req),
109 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
110 }
111 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_start_tx);
112 
113 int gb_audio_apbridgea_stop_tx(struct gb_connection *connection, __u16 i2s_port)
114 {
115 	struct audio_apbridgea_stop_tx_request req;
116 
117 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_STOP_TX;
118 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
119 
120 	return gb_hd_output(connection->hd, &req, sizeof(req),
121 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
122 }
123 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_stop_tx);
124 
125 int gb_audio_apbridgea_shutdown_tx(struct gb_connection *connection,
126 				   __u16 i2s_port)
127 {
128 	struct audio_apbridgea_shutdown_tx_request req;
129 
130 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_SHUTDOWN_TX;
131 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
132 
133 	return gb_hd_output(connection->hd, &req, sizeof(req),
134 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
135 }
136 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_shutdown_tx);
137 
138 int gb_audio_apbridgea_set_rx_data_size(struct gb_connection *connection,
139 					__u16 i2s_port, __u16 size)
140 {
141 	struct audio_apbridgea_set_rx_data_size_request req;
142 
143 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_SET_RX_DATA_SIZE;
144 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
145 	req.size = cpu_to_le16(size);
146 
147 	return gb_hd_output(connection->hd, &req, sizeof(req),
148 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
149 }
150 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_set_rx_data_size);
151 
152 int gb_audio_apbridgea_prepare_rx(struct gb_connection *connection,
153 				  __u16 i2s_port)
154 {
155 	struct audio_apbridgea_prepare_rx_request req;
156 
157 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_PREPARE_RX;
158 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
159 
160 	return gb_hd_output(connection->hd, &req, sizeof(req),
161 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
162 }
163 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_prepare_rx);
164 
165 int gb_audio_apbridgea_start_rx(struct gb_connection *connection,
166 				__u16 i2s_port)
167 {
168 	struct audio_apbridgea_start_rx_request req;
169 
170 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_START_RX;
171 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
172 
173 	return gb_hd_output(connection->hd, &req, sizeof(req),
174 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
175 }
176 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_start_rx);
177 
178 int gb_audio_apbridgea_stop_rx(struct gb_connection *connection, __u16 i2s_port)
179 {
180 	struct audio_apbridgea_stop_rx_request req;
181 
182 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_STOP_RX;
183 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
184 
185 	return gb_hd_output(connection->hd, &req, sizeof(req),
186 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
187 }
188 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_stop_rx);
189 
190 int gb_audio_apbridgea_shutdown_rx(struct gb_connection *connection,
191 				   __u16 i2s_port)
192 {
193 	struct audio_apbridgea_shutdown_rx_request req;
194 
195 	req.hdr.type = AUDIO_APBRIDGEA_TYPE_SHUTDOWN_RX;
196 	req.hdr.i2s_port = cpu_to_le16(i2s_port);
197 
198 	return gb_hd_output(connection->hd, &req, sizeof(req),
199 			    GB_APB_REQUEST_AUDIO_CONTROL, true);
200 }
201 EXPORT_SYMBOL_GPL(gb_audio_apbridgea_shutdown_rx);
202 
203 MODULE_LICENSE("GPL v2");
204 MODULE_ALIAS("greybus:audio-apbridgea");
205 MODULE_DESCRIPTION("Greybus Special APBridgeA Audio Protocol library");
206 MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");
207