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