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