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