]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/staging/greybus/audio_module.c
staging: greybus: add SPDX identifiers to all greybus driver files
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / greybus / audio_module.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Greybus audio driver
4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
6 *
7 * Released under the GPLv2 only.
8 */
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <sound/soc.h>
12 #include <sound/pcm_params.h>
13
14 #include "audio_codec.h"
15 #include "audio_apbridgea.h"
16 #include "audio_manager.h"
17
18 /*
19 * gb_snd management functions
20 */
21
22 static int gbaudio_request_jack(struct gbaudio_module_info *module,
23 struct gb_audio_jack_event_request *req)
24 {
25 int report;
26 struct snd_jack *jack = module->headset_jack.jack;
27 struct snd_jack *btn_jack = module->button_jack.jack;
28
29 if (!jack) {
30 dev_err_ratelimited(module->dev,
31 "Invalid jack event received:type: %u, event: %u\n",
32 req->jack_attribute, req->event);
33 return -EINVAL;
34 }
35
36 dev_warn_ratelimited(module->dev,
37 "Jack Event received: type: %u, event: %u\n",
38 req->jack_attribute, req->event);
39
40 if (req->event == GB_AUDIO_JACK_EVENT_REMOVAL) {
41 module->jack_type = 0;
42 if (btn_jack && module->button_status) {
43 snd_soc_jack_report(&module->button_jack, 0,
44 module->button_mask);
45 module->button_status = 0;
46 }
47 snd_soc_jack_report(&module->headset_jack, 0,
48 module->jack_mask);
49 return 0;
50 }
51
52 report = req->jack_attribute & module->jack_mask;
53 if (!report) {
54 dev_err_ratelimited(module->dev,
55 "Invalid jack event received:type: %u, event: %u\n",
56 req->jack_attribute, req->event);
57 return -EINVAL;
58 }
59
60 if (module->jack_type)
61 dev_warn_ratelimited(module->dev,
62 "Modifying jack from %d to %d\n",
63 module->jack_type, report);
64
65 module->jack_type = report;
66 snd_soc_jack_report(&module->headset_jack, report, module->jack_mask);
67
68 return 0;
69 }
70
71 static int gbaudio_request_button(struct gbaudio_module_info *module,
72 struct gb_audio_button_event_request *req)
73 {
74 int soc_button_id, report;
75 struct snd_jack *btn_jack = module->button_jack.jack;
76
77 if (!btn_jack) {
78 dev_err_ratelimited(module->dev,
79 "Invalid button event received:type: %u, event: %u\n",
80 req->button_id, req->event);
81 return -EINVAL;
82 }
83
84 dev_warn_ratelimited(module->dev,
85 "Button Event received: id: %u, event: %u\n",
86 req->button_id, req->event);
87
88 /* currently supports 4 buttons only */
89 if (!module->jack_type) {
90 dev_err_ratelimited(module->dev,
91 "Jack not present. Bogus event!!\n");
92 return -EINVAL;
93 }
94
95 report = module->button_status & module->button_mask;
96 soc_button_id = 0;
97
98 switch (req->button_id) {
99 case 1:
100 soc_button_id = SND_JACK_BTN_0 & module->button_mask;
101 break;
102
103 case 2:
104 soc_button_id = SND_JACK_BTN_1 & module->button_mask;
105 break;
106
107 case 3:
108 soc_button_id = SND_JACK_BTN_2 & module->button_mask;
109 break;
110
111 case 4:
112 soc_button_id = SND_JACK_BTN_3 & module->button_mask;
113 break;
114 }
115
116 if (!soc_button_id) {
117 dev_err_ratelimited(module->dev,
118 "Invalid button request received\n");
119 return -EINVAL;
120 }
121
122 if (req->event == GB_AUDIO_BUTTON_EVENT_PRESS)
123 report = report | soc_button_id;
124 else
125 report = report & ~soc_button_id;
126
127 module->button_status = report;
128
129 snd_soc_jack_report(&module->button_jack, report, module->button_mask);
130
131 return 0;
132 }
133
134 static int gbaudio_request_stream(struct gbaudio_module_info *module,
135 struct gb_audio_streaming_event_request *req)
136 {
137 dev_warn(module->dev, "Audio Event received: cport: %u, event: %u\n",
138 le16_to_cpu(req->data_cport), req->event);
139
140 return 0;
141 }
142
143 static int gbaudio_codec_request_handler(struct gb_operation *op)
144 {
145 struct gb_connection *connection = op->connection;
146 struct gbaudio_module_info *module =
147 greybus_get_drvdata(connection->bundle);
148 struct gb_operation_msg_hdr *header = op->request->header;
149 struct gb_audio_streaming_event_request *stream_req;
150 struct gb_audio_jack_event_request *jack_req;
151 struct gb_audio_button_event_request *button_req;
152 int ret;
153
154 switch (header->type) {
155 case GB_AUDIO_TYPE_STREAMING_EVENT:
156 stream_req = op->request->payload;
157 ret = gbaudio_request_stream(module, stream_req);
158 break;
159
160 case GB_AUDIO_TYPE_JACK_EVENT:
161 jack_req = op->request->payload;
162 ret = gbaudio_request_jack(module, jack_req);
163 break;
164
165 case GB_AUDIO_TYPE_BUTTON_EVENT:
166 button_req = op->request->payload;
167 ret = gbaudio_request_button(module, button_req);
168 break;
169
170 default:
171 dev_err_ratelimited(&connection->bundle->dev,
172 "Invalid Audio Event received\n");
173 return -EINVAL;
174 }
175
176 return ret;
177 }
178
179 static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule,
180 struct greybus_descriptor_cport *cport_desc,
181 struct gb_bundle *bundle)
182 {
183 struct gb_connection *connection;
184
185 /* Management Cport */
186 if (gbmodule->mgmt_connection) {
187 dev_err(&bundle->dev,
188 "Can't have multiple Management connections\n");
189 return -ENODEV;
190 }
191
192 connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
193 gbaudio_codec_request_handler);
194 if (IS_ERR(connection))
195 return PTR_ERR(connection);
196
197 greybus_set_drvdata(bundle, gbmodule);
198 gbmodule->mgmt_connection = connection;
199
200 return 0;
201 }
202
203 static int gb_audio_add_data_connection(struct gbaudio_module_info *gbmodule,
204 struct greybus_descriptor_cport *cport_desc,
205 struct gb_bundle *bundle)
206 {
207 struct gb_connection *connection;
208 struct gbaudio_data_connection *dai;
209
210 dai = devm_kzalloc(gbmodule->dev, sizeof(*dai), GFP_KERNEL);
211 if (!dai)
212 return -ENOMEM;
213
214 connection = gb_connection_create_offloaded(bundle,
215 le16_to_cpu(cport_desc->id),
216 GB_CONNECTION_FLAG_CSD);
217 if (IS_ERR(connection)) {
218 devm_kfree(gbmodule->dev, dai);
219 return PTR_ERR(connection);
220 }
221
222 greybus_set_drvdata(bundle, gbmodule);
223 dai->id = 0;
224 dai->data_cport = connection->intf_cport_id;
225 dai->connection = connection;
226 list_add(&dai->list, &gbmodule->data_list);
227
228 return 0;
229 }
230
231 /*
232 * This is the basic hook get things initialized and registered w/ gb
233 */
234
235 static int gb_audio_probe(struct gb_bundle *bundle,
236 const struct greybus_bundle_id *id)
237 {
238 struct device *dev = &bundle->dev;
239 struct gbaudio_module_info *gbmodule;
240 struct greybus_descriptor_cport *cport_desc;
241 struct gb_audio_manager_module_descriptor desc;
242 struct gbaudio_data_connection *dai, *_dai;
243 int ret, i;
244 struct gb_audio_topology *topology;
245
246 /* There should be at least one Management and one Data cport */
247 if (bundle->num_cports < 2)
248 return -ENODEV;
249
250 /*
251 * There can be only one Management connection and any number of data
252 * connections.
253 */
254 gbmodule = devm_kzalloc(dev, sizeof(*gbmodule), GFP_KERNEL);
255 if (!gbmodule)
256 return -ENOMEM;
257
258 gbmodule->num_data_connections = bundle->num_cports - 1;
259 INIT_LIST_HEAD(&gbmodule->data_list);
260 INIT_LIST_HEAD(&gbmodule->widget_list);
261 INIT_LIST_HEAD(&gbmodule->ctl_list);
262 INIT_LIST_HEAD(&gbmodule->widget_ctl_list);
263 gbmodule->dev = dev;
264 snprintf(gbmodule->name, NAME_SIZE, "%s.%s", dev->driver->name,
265 dev_name(dev));
266 greybus_set_drvdata(bundle, gbmodule);
267
268 /* Create all connections */
269 for (i = 0; i < bundle->num_cports; i++) {
270 cport_desc = &bundle->cport_desc[i];
271
272 switch (cport_desc->protocol_id) {
273 case GREYBUS_PROTOCOL_AUDIO_MGMT:
274 ret = gb_audio_add_mgmt_connection(gbmodule, cport_desc,
275 bundle);
276 if (ret)
277 goto destroy_connections;
278 break;
279 case GREYBUS_PROTOCOL_AUDIO_DATA:
280 ret = gb_audio_add_data_connection(gbmodule, cport_desc,
281 bundle);
282 if (ret)
283 goto destroy_connections;
284 break;
285 default:
286 dev_err(dev, "Unsupported protocol: 0x%02x\n",
287 cport_desc->protocol_id);
288 ret = -ENODEV;
289 goto destroy_connections;
290 }
291 }
292
293 /* There must be a management cport */
294 if (!gbmodule->mgmt_connection) {
295 ret = -EINVAL;
296 dev_err(dev, "Missing management connection\n");
297 goto destroy_connections;
298 }
299
300 /* Initialize management connection */
301 ret = gb_connection_enable(gbmodule->mgmt_connection);
302 if (ret) {
303 dev_err(dev, "%d: Error while enabling mgmt connection\n", ret);
304 goto destroy_connections;
305 }
306 gbmodule->dev_id = gbmodule->mgmt_connection->intf->interface_id;
307
308 /*
309 * FIXME: malloc for topology happens via audio_gb driver
310 * should be done within codec driver itself
311 */
312 ret = gb_audio_gb_get_topology(gbmodule->mgmt_connection, &topology);
313 if (ret) {
314 dev_err(dev, "%d:Error while fetching topology\n", ret);
315 goto disable_connection;
316 }
317
318 /* process topology data */
319 ret = gbaudio_tplg_parse_data(gbmodule, topology);
320 if (ret) {
321 dev_err(dev, "%d:Error while parsing topology data\n",
322 ret);
323 goto free_topology;
324 }
325 gbmodule->topology = topology;
326
327 /* Initialize data connections */
328 list_for_each_entry(dai, &gbmodule->data_list, list) {
329 ret = gb_connection_enable(dai->connection);
330 if (ret) {
331 dev_err(dev,
332 "%d:Error while enabling %d:data connection\n",
333 ret, dai->data_cport);
334 goto disable_data_connection;
335 }
336 }
337
338 /* register module with gbcodec */
339 ret = gbaudio_register_module(gbmodule);
340 if (ret)
341 goto disable_data_connection;
342
343 /* inform above layer for uevent */
344 dev_dbg(dev, "Inform set_event:%d to above layer\n", 1);
345 /* prepare for the audio manager */
346 strlcpy(desc.name, gbmodule->name, GB_AUDIO_MANAGER_MODULE_NAME_LEN);
347 desc.vid = 2; /* todo */
348 desc.pid = 3; /* todo */
349 desc.intf_id = gbmodule->dev_id;
350 desc.op_devices = gbmodule->op_devices;
351 desc.ip_devices = gbmodule->ip_devices;
352 gbmodule->manager_id = gb_audio_manager_add(&desc);
353
354 dev_dbg(dev, "Add GB Audio device:%s\n", gbmodule->name);
355
356 gb_pm_runtime_put_autosuspend(bundle);
357
358 return 0;
359
360 disable_data_connection:
361 list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list)
362 gb_connection_disable(dai->connection);
363 gbaudio_tplg_release(gbmodule);
364 gbmodule->topology = NULL;
365
366 free_topology:
367 kfree(topology);
368
369 disable_connection:
370 gb_connection_disable(gbmodule->mgmt_connection);
371
372 destroy_connections:
373 list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
374 gb_connection_destroy(dai->connection);
375 list_del(&dai->list);
376 devm_kfree(dev, dai);
377 }
378
379 if (gbmodule->mgmt_connection)
380 gb_connection_destroy(gbmodule->mgmt_connection);
381
382 devm_kfree(dev, gbmodule);
383
384 return ret;
385 }
386
387 static void gb_audio_disconnect(struct gb_bundle *bundle)
388 {
389 struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
390 struct gbaudio_data_connection *dai, *_dai;
391
392 gb_pm_runtime_get_sync(bundle);
393
394 /* cleanup module related resources first */
395 gbaudio_unregister_module(gbmodule);
396
397 /* inform uevent to above layers */
398 gb_audio_manager_remove(gbmodule->manager_id);
399
400 gbaudio_tplg_release(gbmodule);
401 kfree(gbmodule->topology);
402 gbmodule->topology = NULL;
403 gb_connection_disable(gbmodule->mgmt_connection);
404 list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
405 gb_connection_disable(dai->connection);
406 gb_connection_destroy(dai->connection);
407 list_del(&dai->list);
408 devm_kfree(gbmodule->dev, dai);
409 }
410 gb_connection_destroy(gbmodule->mgmt_connection);
411 gbmodule->mgmt_connection = NULL;
412
413 devm_kfree(&bundle->dev, gbmodule);
414 }
415
416 static const struct greybus_bundle_id gb_audio_id_table[] = {
417 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO) },
418 { }
419 };
420 MODULE_DEVICE_TABLE(greybus, gb_audio_id_table);
421
422 #ifdef CONFIG_PM
423 static int gb_audio_suspend(struct device *dev)
424 {
425 struct gb_bundle *bundle = to_gb_bundle(dev);
426 struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
427 struct gbaudio_data_connection *dai;
428
429 list_for_each_entry(dai, &gbmodule->data_list, list)
430 gb_connection_disable(dai->connection);
431
432 gb_connection_disable(gbmodule->mgmt_connection);
433
434 return 0;
435 }
436
437 static int gb_audio_resume(struct device *dev)
438 {
439 struct gb_bundle *bundle = to_gb_bundle(dev);
440 struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
441 struct gbaudio_data_connection *dai;
442 int ret;
443
444 ret = gb_connection_enable(gbmodule->mgmt_connection);
445 if (ret) {
446 dev_err(dev, "%d:Error while enabling mgmt connection\n", ret);
447 return ret;
448 }
449
450 list_for_each_entry(dai, &gbmodule->data_list, list) {
451 ret = gb_connection_enable(dai->connection);
452 if (ret) {
453 dev_err(dev,
454 "%d:Error while enabling %d:data connection\n",
455 ret, dai->data_cport);
456 return ret;
457 }
458 }
459
460 return 0;
461 }
462 #endif
463
464 static const struct dev_pm_ops gb_audio_pm_ops = {
465 SET_RUNTIME_PM_OPS(gb_audio_suspend, gb_audio_resume, NULL)
466 };
467
468 static struct greybus_driver gb_audio_driver = {
469 .name = "gb-audio",
470 .probe = gb_audio_probe,
471 .disconnect = gb_audio_disconnect,
472 .id_table = gb_audio_id_table,
473 .driver.pm = &gb_audio_pm_ops,
474 };
475 module_greybus_driver(gb_audio_driver);
476
477 MODULE_DESCRIPTION("Greybus Audio module driver");
478 MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@linaro.org>");
479 MODULE_LICENSE("GPL v2");
480 MODULE_ALIAS("platform:gbaudio-module");