root/drivers/staging/greybus/audio_module.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gbaudio_request_jack
  2. gbaudio_request_button
  3. gbaudio_request_stream
  4. gbaudio_codec_request_handler
  5. gb_audio_add_mgmt_connection
  6. gb_audio_add_data_connection
  7. gb_audio_probe
  8. gb_audio_disconnect
  9. gb_audio_suspend
  10. gb_audio_resume

   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 
  20 static 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 
  69 static 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 
 132 static 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 
 141 static 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 
 177 static 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 
 201 static 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 = 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 
 233 static 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         gbmodule->dev = dev;
 262         snprintf(gbmodule->name, NAME_SIZE, "%s.%s", dev->driver->name,
 263                  dev_name(dev));
 264         greybus_set_drvdata(bundle, gbmodule);
 265 
 266         /* Create all connections */
 267         for (i = 0; i < bundle->num_cports; i++) {
 268                 cport_desc = &bundle->cport_desc[i];
 269 
 270                 switch (cport_desc->protocol_id) {
 271                 case GREYBUS_PROTOCOL_AUDIO_MGMT:
 272                         ret = gb_audio_add_mgmt_connection(gbmodule, cport_desc,
 273                                                            bundle);
 274                         if (ret)
 275                                 goto destroy_connections;
 276                         break;
 277                 case GREYBUS_PROTOCOL_AUDIO_DATA:
 278                         ret = gb_audio_add_data_connection(gbmodule, cport_desc,
 279                                                            bundle);
 280                         if (ret)
 281                                 goto destroy_connections;
 282                         break;
 283                 default:
 284                         dev_err(dev, "Unsupported protocol: 0x%02x\n",
 285                                 cport_desc->protocol_id);
 286                         ret = -ENODEV;
 287                         goto destroy_connections;
 288                 }
 289         }
 290 
 291         /* There must be a management cport */
 292         if (!gbmodule->mgmt_connection) {
 293                 ret = -EINVAL;
 294                 dev_err(dev, "Missing management connection\n");
 295                 goto destroy_connections;
 296         }
 297 
 298         /* Initialize management connection */
 299         ret = gb_connection_enable(gbmodule->mgmt_connection);
 300         if (ret) {
 301                 dev_err(dev, "%d: Error while enabling mgmt connection\n", ret);
 302                 goto destroy_connections;
 303         }
 304         gbmodule->dev_id = gbmodule->mgmt_connection->intf->interface_id;
 305 
 306         /*
 307          * FIXME: malloc for topology happens via audio_gb driver
 308          * should be done within codec driver itself
 309          */
 310         ret = gb_audio_gb_get_topology(gbmodule->mgmt_connection, &topology);
 311         if (ret) {
 312                 dev_err(dev, "%d:Error while fetching topology\n", ret);
 313                 goto disable_connection;
 314         }
 315 
 316         /* process topology data */
 317         ret = gbaudio_tplg_parse_data(gbmodule, topology);
 318         if (ret) {
 319                 dev_err(dev, "%d:Error while parsing topology data\n",
 320                         ret);
 321                 goto free_topology;
 322         }
 323         gbmodule->topology = topology;
 324 
 325         /* Initialize data connections */
 326         list_for_each_entry(dai, &gbmodule->data_list, list) {
 327                 ret = gb_connection_enable(dai->connection);
 328                 if (ret) {
 329                         dev_err(dev,
 330                                 "%d:Error while enabling %d:data connection\n",
 331                                 ret, dai->data_cport);
 332                         goto disable_data_connection;
 333                 }
 334         }
 335 
 336         /* register module with gbcodec */
 337         ret = gbaudio_register_module(gbmodule);
 338         if (ret)
 339                 goto disable_data_connection;
 340 
 341         /* inform above layer for uevent */
 342         dev_dbg(dev, "Inform set_event:%d to above layer\n", 1);
 343         /* prepare for the audio manager */
 344         strlcpy(desc.name, gbmodule->name, GB_AUDIO_MANAGER_MODULE_NAME_LEN);
 345         desc.vid = 2; /* todo */
 346         desc.pid = 3; /* todo */
 347         desc.intf_id = gbmodule->dev_id;
 348         desc.op_devices = gbmodule->op_devices;
 349         desc.ip_devices = gbmodule->ip_devices;
 350         gbmodule->manager_id = gb_audio_manager_add(&desc);
 351 
 352         dev_dbg(dev, "Add GB Audio device:%s\n", gbmodule->name);
 353 
 354         gb_pm_runtime_put_autosuspend(bundle);
 355 
 356         return 0;
 357 
 358 disable_data_connection:
 359         list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list)
 360                 gb_connection_disable(dai->connection);
 361         gbaudio_tplg_release(gbmodule);
 362         gbmodule->topology = NULL;
 363 
 364 free_topology:
 365         kfree(topology);
 366 
 367 disable_connection:
 368         gb_connection_disable(gbmodule->mgmt_connection);
 369 
 370 destroy_connections:
 371         list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
 372                 gb_connection_destroy(dai->connection);
 373                 list_del(&dai->list);
 374                 devm_kfree(dev, dai);
 375         }
 376 
 377         if (gbmodule->mgmt_connection)
 378                 gb_connection_destroy(gbmodule->mgmt_connection);
 379 
 380         devm_kfree(dev, gbmodule);
 381 
 382         return ret;
 383 }
 384 
 385 static void gb_audio_disconnect(struct gb_bundle *bundle)
 386 {
 387         struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
 388         struct gbaudio_data_connection *dai, *_dai;
 389 
 390         gb_pm_runtime_get_sync(bundle);
 391 
 392         /* cleanup module related resources first */
 393         gbaudio_unregister_module(gbmodule);
 394 
 395         /* inform uevent to above layers */
 396         gb_audio_manager_remove(gbmodule->manager_id);
 397 
 398         gbaudio_tplg_release(gbmodule);
 399         kfree(gbmodule->topology);
 400         gbmodule->topology = NULL;
 401         gb_connection_disable(gbmodule->mgmt_connection);
 402         list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
 403                 gb_connection_disable(dai->connection);
 404                 gb_connection_destroy(dai->connection);
 405                 list_del(&dai->list);
 406                 devm_kfree(gbmodule->dev, dai);
 407         }
 408         gb_connection_destroy(gbmodule->mgmt_connection);
 409         gbmodule->mgmt_connection = NULL;
 410 
 411         devm_kfree(&bundle->dev, gbmodule);
 412 }
 413 
 414 static const struct greybus_bundle_id gb_audio_id_table[] = {
 415         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO) },
 416         { }
 417 };
 418 MODULE_DEVICE_TABLE(greybus, gb_audio_id_table);
 419 
 420 #ifdef CONFIG_PM
 421 static int gb_audio_suspend(struct device *dev)
 422 {
 423         struct gb_bundle *bundle = to_gb_bundle(dev);
 424         struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
 425         struct gbaudio_data_connection *dai;
 426 
 427         list_for_each_entry(dai, &gbmodule->data_list, list)
 428                 gb_connection_disable(dai->connection);
 429 
 430         gb_connection_disable(gbmodule->mgmt_connection);
 431 
 432         return 0;
 433 }
 434 
 435 static int gb_audio_resume(struct device *dev)
 436 {
 437         struct gb_bundle *bundle = to_gb_bundle(dev);
 438         struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
 439         struct gbaudio_data_connection *dai;
 440         int ret;
 441 
 442         ret = gb_connection_enable(gbmodule->mgmt_connection);
 443         if (ret) {
 444                 dev_err(dev, "%d:Error while enabling mgmt connection\n", ret);
 445                 return ret;
 446         }
 447 
 448         list_for_each_entry(dai, &gbmodule->data_list, list) {
 449                 ret = gb_connection_enable(dai->connection);
 450                 if (ret) {
 451                         dev_err(dev,
 452                                 "%d:Error while enabling %d:data connection\n",
 453                                 ret, dai->data_cport);
 454                         return ret;
 455                 }
 456         }
 457 
 458         return 0;
 459 }
 460 #endif
 461 
 462 static const struct dev_pm_ops gb_audio_pm_ops = {
 463         SET_RUNTIME_PM_OPS(gb_audio_suspend, gb_audio_resume, NULL)
 464 };
 465 
 466 static struct greybus_driver gb_audio_driver = {
 467         .name           = "gb-audio",
 468         .probe          = gb_audio_probe,
 469         .disconnect     = gb_audio_disconnect,
 470         .id_table       = gb_audio_id_table,
 471         .driver.pm      = &gb_audio_pm_ops,
 472 };
 473 module_greybus_driver(gb_audio_driver);
 474 
 475 MODULE_DESCRIPTION("Greybus Audio module driver");
 476 MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@linaro.org>");
 477 MODULE_LICENSE("GPL v2");
 478 MODULE_ALIAS("platform:gbaudio-module");

/* [<][>][^][v][top][bottom][index][help] */