Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Greybus audio driver
0004  * Copyright 2015 Google Inc.
0005  * Copyright 2015 Linaro Ltd.
0006  */
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <sound/soc.h>
0010 #include <sound/pcm_params.h>
0011 
0012 #include "audio_codec.h"
0013 #include "audio_apbridgea.h"
0014 #include "audio_manager.h"
0015 
0016 /*
0017  * gb_snd management functions
0018  */
0019 
0020 static int gbaudio_request_jack(struct gbaudio_module_info *module,
0021                 struct gb_audio_jack_event_request *req)
0022 {
0023     int report;
0024     struct snd_jack *jack = module->headset.jack.jack;
0025     struct snd_jack *btn_jack = module->button.jack.jack;
0026 
0027     if (!jack) {
0028         dev_err_ratelimited(module->dev,
0029                     "Invalid jack event received:type: %u, event: %u\n",
0030                     req->jack_attribute, req->event);
0031         return -EINVAL;
0032     }
0033 
0034     dev_warn_ratelimited(module->dev,
0035                  "Jack Event received: type: %u, event: %u\n",
0036                  req->jack_attribute, req->event);
0037 
0038     if (req->event == GB_AUDIO_JACK_EVENT_REMOVAL) {
0039         module->jack_type = 0;
0040         if (btn_jack && module->button_status) {
0041             snd_soc_jack_report(&module->button.jack, 0,
0042                         module->button_mask);
0043             module->button_status = 0;
0044         }
0045         snd_soc_jack_report(&module->headset.jack, 0,
0046                     module->jack_mask);
0047         return 0;
0048     }
0049 
0050     report = req->jack_attribute & module->jack_mask;
0051     if (!report) {
0052         dev_err_ratelimited(module->dev,
0053                     "Invalid jack event received:type: %u, event: %u\n",
0054                     req->jack_attribute, req->event);
0055         return -EINVAL;
0056     }
0057 
0058     if (module->jack_type)
0059         dev_warn_ratelimited(module->dev,
0060                      "Modifying jack from %d to %d\n",
0061                      module->jack_type, report);
0062 
0063     module->jack_type = report;
0064     snd_soc_jack_report(&module->headset.jack, report, module->jack_mask);
0065 
0066     return 0;
0067 }
0068 
0069 static int gbaudio_request_button(struct gbaudio_module_info *module,
0070                   struct gb_audio_button_event_request *req)
0071 {
0072     int soc_button_id, report;
0073     struct snd_jack *btn_jack = module->button.jack.jack;
0074 
0075     if (!btn_jack) {
0076         dev_err_ratelimited(module->dev,
0077                     "Invalid button event received:type: %u, event: %u\n",
0078                     req->button_id, req->event);
0079         return -EINVAL;
0080     }
0081 
0082     dev_warn_ratelimited(module->dev,
0083                  "Button Event received: id: %u, event: %u\n",
0084                  req->button_id, req->event);
0085 
0086     /* currently supports 4 buttons only */
0087     if (!module->jack_type) {
0088         dev_err_ratelimited(module->dev,
0089                     "Jack not present. Bogus event!!\n");
0090         return -EINVAL;
0091     }
0092 
0093     report = module->button_status & module->button_mask;
0094     soc_button_id = 0;
0095 
0096     switch (req->button_id) {
0097     case 1:
0098         soc_button_id = SND_JACK_BTN_0 & module->button_mask;
0099         break;
0100 
0101     case 2:
0102         soc_button_id = SND_JACK_BTN_1 & module->button_mask;
0103         break;
0104 
0105     case 3:
0106         soc_button_id = SND_JACK_BTN_2 & module->button_mask;
0107         break;
0108 
0109     case 4:
0110         soc_button_id = SND_JACK_BTN_3 & module->button_mask;
0111         break;
0112     }
0113 
0114     if (!soc_button_id) {
0115         dev_err_ratelimited(module->dev,
0116                     "Invalid button request received\n");
0117         return -EINVAL;
0118     }
0119 
0120     if (req->event == GB_AUDIO_BUTTON_EVENT_PRESS)
0121         report = report | soc_button_id;
0122     else
0123         report = report & ~soc_button_id;
0124 
0125     module->button_status = report;
0126 
0127     snd_soc_jack_report(&module->button.jack, report, module->button_mask);
0128 
0129     return 0;
0130 }
0131 
0132 static int gbaudio_request_stream(struct gbaudio_module_info *module,
0133                   struct gb_audio_streaming_event_request *req)
0134 {
0135     dev_warn(module->dev, "Audio Event received: cport: %u, event: %u\n",
0136          le16_to_cpu(req->data_cport), req->event);
0137 
0138     return 0;
0139 }
0140 
0141 static int gbaudio_codec_request_handler(struct gb_operation *op)
0142 {
0143     struct gb_connection *connection = op->connection;
0144     struct gbaudio_module_info *module =
0145         greybus_get_drvdata(connection->bundle);
0146     struct gb_operation_msg_hdr *header = op->request->header;
0147     struct gb_audio_streaming_event_request *stream_req;
0148     struct gb_audio_jack_event_request *jack_req;
0149     struct gb_audio_button_event_request *button_req;
0150     int ret;
0151 
0152     switch (header->type) {
0153     case GB_AUDIO_TYPE_STREAMING_EVENT:
0154         stream_req = op->request->payload;
0155         ret = gbaudio_request_stream(module, stream_req);
0156         break;
0157 
0158     case GB_AUDIO_TYPE_JACK_EVENT:
0159         jack_req = op->request->payload;
0160         ret = gbaudio_request_jack(module, jack_req);
0161         break;
0162 
0163     case GB_AUDIO_TYPE_BUTTON_EVENT:
0164         button_req = op->request->payload;
0165         ret = gbaudio_request_button(module, button_req);
0166         break;
0167 
0168     default:
0169         dev_err_ratelimited(&connection->bundle->dev,
0170                     "Invalid Audio Event received\n");
0171         return -EINVAL;
0172     }
0173 
0174     return ret;
0175 }
0176 
0177 static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule,
0178                     struct greybus_descriptor_cport *cport_desc,
0179                     struct gb_bundle *bundle)
0180 {
0181     struct gb_connection *connection;
0182 
0183     /* Management Cport */
0184     if (gbmodule->mgmt_connection) {
0185         dev_err(&bundle->dev,
0186             "Can't have multiple Management connections\n");
0187         return -ENODEV;
0188     }
0189 
0190     connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
0191                       gbaudio_codec_request_handler);
0192     if (IS_ERR(connection))
0193         return PTR_ERR(connection);
0194 
0195     greybus_set_drvdata(bundle, gbmodule);
0196     gbmodule->mgmt_connection = connection;
0197 
0198     return 0;
0199 }
0200 
0201 static int gb_audio_add_data_connection(struct gbaudio_module_info *gbmodule,
0202                     struct greybus_descriptor_cport *cport_desc,
0203                     struct gb_bundle *bundle)
0204 {
0205     struct gb_connection *connection;
0206     struct gbaudio_data_connection *dai;
0207 
0208     dai = devm_kzalloc(gbmodule->dev, sizeof(*dai), GFP_KERNEL);
0209     if (!dai)
0210         return -ENOMEM;
0211 
0212     connection = gb_connection_create_offloaded(bundle,
0213                             le16_to_cpu(cport_desc->id),
0214                             GB_CONNECTION_FLAG_CSD);
0215     if (IS_ERR(connection)) {
0216         devm_kfree(gbmodule->dev, dai);
0217         return PTR_ERR(connection);
0218     }
0219 
0220     greybus_set_drvdata(bundle, gbmodule);
0221     dai->id = 0;
0222     dai->data_cport = cpu_to_le16(connection->intf_cport_id);
0223     dai->connection = connection;
0224     list_add(&dai->list, &gbmodule->data_list);
0225 
0226     return 0;
0227 }
0228 
0229 /*
0230  * This is the basic hook get things initialized and registered w/ gb
0231  */
0232 
0233 static int gb_audio_probe(struct gb_bundle *bundle,
0234               const struct greybus_bundle_id *id)
0235 {
0236     struct device *dev = &bundle->dev;
0237     struct gbaudio_module_info *gbmodule;
0238     struct greybus_descriptor_cport *cport_desc;
0239     struct gb_audio_manager_module_descriptor desc;
0240     struct gbaudio_data_connection *dai, *_dai;
0241     int ret, i;
0242     struct gb_audio_topology *topology;
0243 
0244     /* There should be at least one Management and one Data cport */
0245     if (bundle->num_cports < 2)
0246         return -ENODEV;
0247 
0248     /*
0249      * There can be only one Management connection and any number of data
0250      * connections.
0251      */
0252     gbmodule = devm_kzalloc(dev, sizeof(*gbmodule), GFP_KERNEL);
0253     if (!gbmodule)
0254         return -ENOMEM;
0255 
0256     gbmodule->num_data_connections = bundle->num_cports - 1;
0257     INIT_LIST_HEAD(&gbmodule->data_list);
0258     INIT_LIST_HEAD(&gbmodule->widget_list);
0259     INIT_LIST_HEAD(&gbmodule->ctl_list);
0260     INIT_LIST_HEAD(&gbmodule->widget_ctl_list);
0261     INIT_LIST_HEAD(&gbmodule->jack_list);
0262     gbmodule->dev = dev;
0263     snprintf(gbmodule->name, sizeof(gbmodule->name), "%s.%s", dev->driver->name,
0264          dev_name(dev));
0265     greybus_set_drvdata(bundle, gbmodule);
0266 
0267     /* Create all connections */
0268     for (i = 0; i < bundle->num_cports; i++) {
0269         cport_desc = &bundle->cport_desc[i];
0270 
0271         switch (cport_desc->protocol_id) {
0272         case GREYBUS_PROTOCOL_AUDIO_MGMT:
0273             ret = gb_audio_add_mgmt_connection(gbmodule, cport_desc,
0274                                bundle);
0275             if (ret)
0276                 goto destroy_connections;
0277             break;
0278         case GREYBUS_PROTOCOL_AUDIO_DATA:
0279             ret = gb_audio_add_data_connection(gbmodule, cport_desc,
0280                                bundle);
0281             if (ret)
0282                 goto destroy_connections;
0283             break;
0284         default:
0285             dev_err(dev, "Unsupported protocol: 0x%02x\n",
0286                 cport_desc->protocol_id);
0287             ret = -ENODEV;
0288             goto destroy_connections;
0289         }
0290     }
0291 
0292     /* There must be a management cport */
0293     if (!gbmodule->mgmt_connection) {
0294         ret = -EINVAL;
0295         dev_err(dev, "Missing management connection\n");
0296         goto destroy_connections;
0297     }
0298 
0299     /* Initialize management connection */
0300     ret = gb_connection_enable(gbmodule->mgmt_connection);
0301     if (ret) {
0302         dev_err(dev, "%d: Error while enabling mgmt connection\n", ret);
0303         goto destroy_connections;
0304     }
0305     gbmodule->dev_id = gbmodule->mgmt_connection->intf->interface_id;
0306 
0307     /*
0308      * FIXME: malloc for topology happens via audio_gb driver
0309      * should be done within codec driver itself
0310      */
0311     ret = gb_audio_gb_get_topology(gbmodule->mgmt_connection, &topology);
0312     if (ret) {
0313         dev_err(dev, "%d:Error while fetching topology\n", ret);
0314         goto disable_connection;
0315     }
0316 
0317     /* process topology data */
0318     ret = gbaudio_tplg_parse_data(gbmodule, topology);
0319     if (ret) {
0320         dev_err(dev, "%d:Error while parsing topology data\n",
0321             ret);
0322         goto free_topology;
0323     }
0324     gbmodule->topology = topology;
0325 
0326     /* Initialize data connections */
0327     list_for_each_entry(dai, &gbmodule->data_list, list) {
0328         ret = gb_connection_enable(dai->connection);
0329         if (ret) {
0330             dev_err(dev,
0331                 "%d:Error while enabling %d:data connection\n",
0332                 ret, le16_to_cpu(dai->data_cport));
0333             goto disable_data_connection;
0334         }
0335     }
0336 
0337     /* register module with gbcodec */
0338     ret = gbaudio_register_module(gbmodule);
0339     if (ret)
0340         goto disable_data_connection;
0341 
0342     /* inform above layer for uevent */
0343     dev_dbg(dev, "Inform set_event:%d to above layer\n", 1);
0344     /* prepare for the audio manager */
0345     strscpy(desc.name, gbmodule->name, sizeof(desc.name));
0346     desc.vid = 2; /* todo */
0347     desc.pid = 3; /* todo */
0348     desc.intf_id = gbmodule->dev_id;
0349     desc.op_devices = gbmodule->op_devices;
0350     desc.ip_devices = gbmodule->ip_devices;
0351     gbmodule->manager_id = gb_audio_manager_add(&desc);
0352 
0353     dev_dbg(dev, "Add GB Audio device:%s\n", gbmodule->name);
0354 
0355     gb_pm_runtime_put_autosuspend(bundle);
0356 
0357     return 0;
0358 
0359 disable_data_connection:
0360     list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list)
0361         gb_connection_disable(dai->connection);
0362     gbaudio_tplg_release(gbmodule);
0363     gbmodule->topology = NULL;
0364 
0365 free_topology:
0366     kfree(topology);
0367 
0368 disable_connection:
0369     gb_connection_disable(gbmodule->mgmt_connection);
0370 
0371 destroy_connections:
0372     list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
0373         gb_connection_destroy(dai->connection);
0374         list_del(&dai->list);
0375         devm_kfree(dev, dai);
0376     }
0377 
0378     if (gbmodule->mgmt_connection)
0379         gb_connection_destroy(gbmodule->mgmt_connection);
0380 
0381     devm_kfree(dev, gbmodule);
0382 
0383     return ret;
0384 }
0385 
0386 static void gb_audio_disconnect(struct gb_bundle *bundle)
0387 {
0388     struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
0389     struct gbaudio_data_connection *dai, *_dai;
0390 
0391     gb_pm_runtime_get_sync(bundle);
0392 
0393     /* cleanup module related resources first */
0394     gbaudio_unregister_module(gbmodule);
0395 
0396     /* inform uevent to above layers */
0397     gb_audio_manager_remove(gbmodule->manager_id);
0398 
0399     gbaudio_tplg_release(gbmodule);
0400     kfree(gbmodule->topology);
0401     gbmodule->topology = NULL;
0402     gb_connection_disable(gbmodule->mgmt_connection);
0403     list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
0404         gb_connection_disable(dai->connection);
0405         gb_connection_destroy(dai->connection);
0406         list_del(&dai->list);
0407         devm_kfree(gbmodule->dev, dai);
0408     }
0409     gb_connection_destroy(gbmodule->mgmt_connection);
0410     gbmodule->mgmt_connection = NULL;
0411 
0412     devm_kfree(&bundle->dev, gbmodule);
0413 }
0414 
0415 static const struct greybus_bundle_id gb_audio_id_table[] = {
0416     { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO) },
0417     { }
0418 };
0419 MODULE_DEVICE_TABLE(greybus, gb_audio_id_table);
0420 
0421 #ifdef CONFIG_PM
0422 static int gb_audio_suspend(struct device *dev)
0423 {
0424     struct gb_bundle *bundle = to_gb_bundle(dev);
0425     struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
0426     struct gbaudio_data_connection *dai;
0427 
0428     list_for_each_entry(dai, &gbmodule->data_list, list)
0429         gb_connection_disable(dai->connection);
0430 
0431     gb_connection_disable(gbmodule->mgmt_connection);
0432 
0433     return 0;
0434 }
0435 
0436 static int gb_audio_resume(struct device *dev)
0437 {
0438     struct gb_bundle *bundle = to_gb_bundle(dev);
0439     struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
0440     struct gbaudio_data_connection *dai;
0441     int ret;
0442 
0443     ret = gb_connection_enable(gbmodule->mgmt_connection);
0444     if (ret) {
0445         dev_err(dev, "%d:Error while enabling mgmt connection\n", ret);
0446         return ret;
0447     }
0448 
0449     list_for_each_entry(dai, &gbmodule->data_list, list) {
0450         ret = gb_connection_enable(dai->connection);
0451         if (ret) {
0452             dev_err(dev,
0453                 "%d:Error while enabling %d:data connection\n",
0454                 ret, le16_to_cpu(dai->data_cport));
0455             return ret;
0456         }
0457     }
0458 
0459     return 0;
0460 }
0461 #endif
0462 
0463 static const struct dev_pm_ops gb_audio_pm_ops = {
0464     SET_RUNTIME_PM_OPS(gb_audio_suspend, gb_audio_resume, NULL)
0465 };
0466 
0467 static struct greybus_driver gb_audio_driver = {
0468     .name       = "gb-audio",
0469     .probe      = gb_audio_probe,
0470     .disconnect = gb_audio_disconnect,
0471     .id_table   = gb_audio_id_table,
0472     .driver.pm  = &gb_audio_pm_ops,
0473 };
0474 module_greybus_driver(gb_audio_driver);
0475 
0476 MODULE_DESCRIPTION("Greybus Audio module driver");
0477 MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@linaro.org>");
0478 MODULE_LICENSE("GPL v2");
0479 MODULE_ALIAS("platform:gbaudio-module");