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 "operation.h"
11 #include "audio_codec.h"
12 
13 /* TODO: Split into separate calls */
gb_audio_gb_get_topology(struct gb_connection * connection,struct gb_audio_topology ** topology)14 int gb_audio_gb_get_topology(struct gb_connection *connection,
15 			     struct gb_audio_topology **topology)
16 {
17 	struct gb_audio_get_topology_size_response size_resp;
18 	struct gb_audio_topology *topo;
19 	u16 size;
20 	int ret;
21 
22 	ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY_SIZE,
23 				NULL, 0, &size_resp, sizeof(size_resp));
24 	if (ret)
25 		return ret;
26 
27 	size = le16_to_cpu(size_resp.size);
28 	if (size < sizeof(*topo))
29 		return -ENODATA;
30 
31 	topo = kzalloc(size, GFP_KERNEL);
32 	if (!topo)
33 		return -ENOMEM;
34 
35 	ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_TOPOLOGY, NULL, 0,
36 				topo, size);
37 	if (ret) {
38 		kfree(topo);
39 		return ret;
40 	}
41 
42 	*topology = topo;
43 
44 	return 0;
45 }
46 EXPORT_SYMBOL_GPL(gb_audio_gb_get_topology);
47 
gb_audio_gb_get_control(struct gb_connection * connection,u8 control_id,u8 index,struct gb_audio_ctl_elem_value * value)48 int gb_audio_gb_get_control(struct gb_connection *connection,
49 			    u8 control_id, u8 index,
50 			    struct gb_audio_ctl_elem_value *value)
51 {
52 	struct gb_audio_get_control_request req;
53 	struct gb_audio_get_control_response resp;
54 	int ret;
55 
56 	req.control_id = control_id;
57 	req.index = index;
58 
59 	ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_CONTROL,
60 				&req, sizeof(req), &resp, sizeof(resp));
61 	if (ret)
62 		return ret;
63 
64 	memcpy(value, &resp.value, sizeof(*value));
65 
66 	return 0;
67 }
68 EXPORT_SYMBOL_GPL(gb_audio_gb_get_control);
69 
gb_audio_gb_set_control(struct gb_connection * connection,u8 control_id,u8 index,struct gb_audio_ctl_elem_value * value)70 int gb_audio_gb_set_control(struct gb_connection *connection,
71 			    u8 control_id, u8 index,
72 			    struct gb_audio_ctl_elem_value *value)
73 {
74 	struct gb_audio_set_control_request req;
75 
76 	req.control_id = control_id;
77 	req.index = index;
78 	memcpy(&req.value, value, sizeof(req.value));
79 
80 	return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_CONTROL,
81 				 &req, sizeof(req), NULL, 0);
82 }
83 EXPORT_SYMBOL_GPL(gb_audio_gb_set_control);
84 
gb_audio_gb_enable_widget(struct gb_connection * connection,u8 widget_id)85 int gb_audio_gb_enable_widget(struct gb_connection *connection,
86 			      u8 widget_id)
87 {
88 	struct gb_audio_enable_widget_request req;
89 
90 	req.widget_id = widget_id;
91 
92 	return gb_operation_sync(connection, GB_AUDIO_TYPE_ENABLE_WIDGET,
93 				 &req, sizeof(req), NULL, 0);
94 }
95 EXPORT_SYMBOL_GPL(gb_audio_gb_enable_widget);
96 
gb_audio_gb_disable_widget(struct gb_connection * connection,u8 widget_id)97 int gb_audio_gb_disable_widget(struct gb_connection *connection,
98 			       u8 widget_id)
99 {
100 	struct gb_audio_disable_widget_request req;
101 
102 	req.widget_id = widget_id;
103 
104 	return gb_operation_sync(connection, GB_AUDIO_TYPE_DISABLE_WIDGET,
105 				 &req, sizeof(req), NULL, 0);
106 }
107 EXPORT_SYMBOL_GPL(gb_audio_gb_disable_widget);
108 
gb_audio_gb_get_pcm(struct gb_connection * connection,u16 data_cport,u32 * format,u32 * rate,u8 * channels,u8 * sig_bits)109 int gb_audio_gb_get_pcm(struct gb_connection *connection, u16 data_cport,
110 			u32 *format, u32 *rate, u8 *channels,
111 			u8 *sig_bits)
112 {
113 	struct gb_audio_get_pcm_request req;
114 	struct gb_audio_get_pcm_response resp;
115 	int ret;
116 
117 	req.data_cport = cpu_to_le16(data_cport);
118 
119 	ret = gb_operation_sync(connection, GB_AUDIO_TYPE_GET_PCM,
120 				&req, sizeof(req), &resp, sizeof(resp));
121 	if (ret)
122 		return ret;
123 
124 	*format = le32_to_cpu(resp.format);
125 	*rate = le32_to_cpu(resp.rate);
126 	*channels = resp.channels;
127 	*sig_bits = resp.sig_bits;
128 
129 	return 0;
130 }
131 EXPORT_SYMBOL_GPL(gb_audio_gb_get_pcm);
132 
gb_audio_gb_set_pcm(struct gb_connection * connection,u16 data_cport,u32 format,u32 rate,u8 channels,u8 sig_bits)133 int gb_audio_gb_set_pcm(struct gb_connection *connection, u16 data_cport,
134 			u32 format, u32 rate, u8 channels,
135 			u8 sig_bits)
136 {
137 	struct gb_audio_set_pcm_request req;
138 
139 	req.data_cport = cpu_to_le16(data_cport);
140 	req.format = cpu_to_le32(format);
141 	req.rate = cpu_to_le32(rate);
142 	req.channels = channels;
143 	req.sig_bits = sig_bits;
144 
145 	return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_PCM,
146 				 &req, sizeof(req), NULL, 0);
147 }
148 EXPORT_SYMBOL_GPL(gb_audio_gb_set_pcm);
149 
gb_audio_gb_set_tx_data_size(struct gb_connection * connection,u16 data_cport,u16 size)150 int gb_audio_gb_set_tx_data_size(struct gb_connection *connection,
151 				 u16 data_cport, u16 size)
152 {
153 	struct gb_audio_set_tx_data_size_request req;
154 
155 	req.data_cport = cpu_to_le16(data_cport);
156 	req.size = cpu_to_le16(size);
157 
158 	return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_TX_DATA_SIZE,
159 				 &req, sizeof(req), NULL, 0);
160 }
161 EXPORT_SYMBOL_GPL(gb_audio_gb_set_tx_data_size);
162 
gb_audio_gb_activate_tx(struct gb_connection * connection,u16 data_cport)163 int gb_audio_gb_activate_tx(struct gb_connection *connection,
164 			    u16 data_cport)
165 {
166 	struct gb_audio_activate_tx_request req;
167 
168 	req.data_cport = cpu_to_le16(data_cport);
169 
170 	return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_TX,
171 				 &req, sizeof(req), NULL, 0);
172 }
173 EXPORT_SYMBOL_GPL(gb_audio_gb_activate_tx);
174 
gb_audio_gb_deactivate_tx(struct gb_connection * connection,u16 data_cport)175 int gb_audio_gb_deactivate_tx(struct gb_connection *connection,
176 			      u16 data_cport)
177 {
178 	struct gb_audio_deactivate_tx_request req;
179 
180 	req.data_cport = cpu_to_le16(data_cport);
181 
182 	return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_TX,
183 				 &req, sizeof(req), NULL, 0);
184 }
185 EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_tx);
186 
gb_audio_gb_set_rx_data_size(struct gb_connection * connection,u16 data_cport,u16 size)187 int gb_audio_gb_set_rx_data_size(struct gb_connection *connection,
188 				 u16 data_cport, u16 size)
189 {
190 	struct gb_audio_set_rx_data_size_request req;
191 
192 	req.data_cport = cpu_to_le16(data_cport);
193 	req.size = cpu_to_le16(size);
194 
195 	return gb_operation_sync(connection, GB_AUDIO_TYPE_SET_RX_DATA_SIZE,
196 				 &req, sizeof(req), NULL, 0);
197 }
198 EXPORT_SYMBOL_GPL(gb_audio_gb_set_rx_data_size);
199 
gb_audio_gb_activate_rx(struct gb_connection * connection,u16 data_cport)200 int gb_audio_gb_activate_rx(struct gb_connection *connection,
201 			    u16 data_cport)
202 {
203 	struct gb_audio_activate_rx_request req;
204 
205 	req.data_cport = cpu_to_le16(data_cport);
206 
207 	return gb_operation_sync(connection, GB_AUDIO_TYPE_ACTIVATE_RX,
208 				 &req, sizeof(req), NULL, 0);
209 }
210 EXPORT_SYMBOL_GPL(gb_audio_gb_activate_rx);
211 
gb_audio_gb_deactivate_rx(struct gb_connection * connection,u16 data_cport)212 int gb_audio_gb_deactivate_rx(struct gb_connection *connection,
213 			      u16 data_cport)
214 {
215 	struct gb_audio_deactivate_rx_request req;
216 
217 	req.data_cport = cpu_to_le16(data_cport);
218 
219 	return gb_operation_sync(connection, GB_AUDIO_TYPE_DEACTIVATE_RX,
220 				 &req, sizeof(req), NULL, 0);
221 }
222 EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_rx);
223 
224 MODULE_LICENSE("GPL v2");
225 MODULE_ALIAS("greybus:audio-gb");
226 MODULE_DESCRIPTION("Greybus Audio Device Class Protocol library");
227 MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");
228