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 */ |
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, request_size: 0, response: &size_resp, response_size: 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, request_size: 0, |
34 | response: topo, response_size: size); |
35 | if (ret) { |
36 | kfree(objp: topo); |
37 | return ret; |
38 | } |
39 | |
40 | *topology = topo; |
41 | |
42 | return 0; |
43 | } |
44 | EXPORT_SYMBOL_GPL(gb_audio_gb_get_topology); |
45 | |
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 | request: &req, request_size: sizeof(req), response: &resp, response_size: 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 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
80 | } |
81 | EXPORT_SYMBOL_GPL(gb_audio_gb_set_control); |
82 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
92 | } |
93 | EXPORT_SYMBOL_GPL(gb_audio_gb_enable_widget); |
94 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
104 | } |
105 | EXPORT_SYMBOL_GPL(gb_audio_gb_disable_widget); |
106 | |
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 | request: &req, request_size: sizeof(req), response: &resp, response_size: 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 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
145 | } |
146 | EXPORT_SYMBOL_GPL(gb_audio_gb_set_pcm); |
147 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
158 | } |
159 | EXPORT_SYMBOL_GPL(gb_audio_gb_set_tx_data_size); |
160 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
170 | } |
171 | EXPORT_SYMBOL_GPL(gb_audio_gb_activate_tx); |
172 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
182 | } |
183 | EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_tx); |
184 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
195 | } |
196 | EXPORT_SYMBOL_GPL(gb_audio_gb_set_rx_data_size); |
197 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
207 | } |
208 | EXPORT_SYMBOL_GPL(gb_audio_gb_activate_rx); |
209 | |
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 | request: &req, request_size: sizeof(req), NULL, response_size: 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 | |