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 */
12int 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}
44EXPORT_SYMBOL_GPL(gb_audio_gb_get_topology);
45
46int 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}
66EXPORT_SYMBOL_GPL(gb_audio_gb_get_control);
67
68int 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}
81EXPORT_SYMBOL_GPL(gb_audio_gb_set_control);
82
83int 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}
93EXPORT_SYMBOL_GPL(gb_audio_gb_enable_widget);
94
95int 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}
105EXPORT_SYMBOL_GPL(gb_audio_gb_disable_widget);
106
107int 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}
129EXPORT_SYMBOL_GPL(gb_audio_gb_get_pcm);
130
131int 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}
146EXPORT_SYMBOL_GPL(gb_audio_gb_set_pcm);
147
148int 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}
159EXPORT_SYMBOL_GPL(gb_audio_gb_set_tx_data_size);
160
161int 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}
171EXPORT_SYMBOL_GPL(gb_audio_gb_activate_tx);
172
173int 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}
183EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_tx);
184
185int 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}
196EXPORT_SYMBOL_GPL(gb_audio_gb_set_rx_data_size);
197
198int 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}
208EXPORT_SYMBOL_GPL(gb_audio_gb_activate_rx);
209
210int 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}
220EXPORT_SYMBOL_GPL(gb_audio_gb_deactivate_rx);
221
222MODULE_LICENSE("GPL v2");
223MODULE_ALIAS("greybus:audio-gb");
224MODULE_DESCRIPTION("Greybus Audio Device Class Protocol library");
225MODULE_AUTHOR("Mark Greer <mgreer@animalcreek.com>");
226

source code of linux/drivers/staging/greybus/audio_gb.c