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