1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
7 * Released under the GPLv2 only.
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <sound/soc.h>
12 #include <sound/pcm_params.h>
14 #include "audio_codec.h"
15 #include "audio_apbridgea.h"
16 #include "audio_manager.h"
19 * gb_snd management functions
22 static int gbaudio_request_jack(struct gbaudio_module_info
*module
,
23 struct gb_audio_jack_event_request
*req
)
26 struct snd_jack
*jack
= module
->headset_jack
.jack
;
27 struct snd_jack
*btn_jack
= module
->button_jack
.jack
;
30 dev_err_ratelimited(module
->dev
,
31 "Invalid jack event received:type: %u, event: %u\n",
32 req
->jack_attribute
, req
->event
);
36 dev_warn_ratelimited(module
->dev
,
37 "Jack Event received: type: %u, event: %u\n",
38 req
->jack_attribute
, req
->event
);
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,
45 module
->button_status
= 0;
47 snd_soc_jack_report(&module
->headset_jack
, 0,
52 report
= req
->jack_attribute
& module
->jack_mask
;
54 dev_err_ratelimited(module
->dev
,
55 "Invalid jack event received:type: %u, event: %u\n",
56 req
->jack_attribute
, req
->event
);
60 if (module
->jack_type
)
61 dev_warn_ratelimited(module
->dev
,
62 "Modifying jack from %d to %d\n",
63 module
->jack_type
, report
);
65 module
->jack_type
= report
;
66 snd_soc_jack_report(&module
->headset_jack
, report
, module
->jack_mask
);
71 static int gbaudio_request_button(struct gbaudio_module_info
*module
,
72 struct gb_audio_button_event_request
*req
)
74 int soc_button_id
, report
;
75 struct snd_jack
*btn_jack
= module
->button_jack
.jack
;
78 dev_err_ratelimited(module
->dev
,
79 "Invalid button event received:type: %u, event: %u\n",
80 req
->button_id
, req
->event
);
84 dev_warn_ratelimited(module
->dev
,
85 "Button Event received: id: %u, event: %u\n",
86 req
->button_id
, req
->event
);
88 /* currently supports 4 buttons only */
89 if (!module
->jack_type
) {
90 dev_err_ratelimited(module
->dev
,
91 "Jack not present. Bogus event!!\n");
95 report
= module
->button_status
& module
->button_mask
;
98 switch (req
->button_id
) {
100 soc_button_id
= SND_JACK_BTN_0
& module
->button_mask
;
104 soc_button_id
= SND_JACK_BTN_1
& module
->button_mask
;
108 soc_button_id
= SND_JACK_BTN_2
& module
->button_mask
;
112 soc_button_id
= SND_JACK_BTN_3
& module
->button_mask
;
116 if (!soc_button_id
) {
117 dev_err_ratelimited(module
->dev
,
118 "Invalid button request received\n");
122 if (req
->event
== GB_AUDIO_BUTTON_EVENT_PRESS
)
123 report
= report
| soc_button_id
;
125 report
= report
& ~soc_button_id
;
127 module
->button_status
= report
;
129 snd_soc_jack_report(&module
->button_jack
, report
, module
->button_mask
);
134 static int gbaudio_request_stream(struct gbaudio_module_info
*module
,
135 struct gb_audio_streaming_event_request
*req
)
137 dev_warn(module
->dev
, "Audio Event received: cport: %u, event: %u\n",
138 le16_to_cpu(req
->data_cport
), req
->event
);
143 static int gbaudio_codec_request_handler(struct gb_operation
*op
)
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
;
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
);
160 case GB_AUDIO_TYPE_JACK_EVENT
:
161 jack_req
= op
->request
->payload
;
162 ret
= gbaudio_request_jack(module
, jack_req
);
165 case GB_AUDIO_TYPE_BUTTON_EVENT
:
166 button_req
= op
->request
->payload
;
167 ret
= gbaudio_request_button(module
, button_req
);
171 dev_err_ratelimited(&connection
->bundle
->dev
,
172 "Invalid Audio Event received\n");
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
)
183 struct gb_connection
*connection
;
185 /* Management Cport */
186 if (gbmodule
->mgmt_connection
) {
187 dev_err(&bundle
->dev
,
188 "Can't have multiple Management connections\n");
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
);
197 greybus_set_drvdata(bundle
, gbmodule
);
198 gbmodule
->mgmt_connection
= connection
;
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
)
207 struct gb_connection
*connection
;
208 struct gbaudio_data_connection
*dai
;
210 dai
= devm_kzalloc(gbmodule
->dev
, sizeof(*dai
), GFP_KERNEL
);
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
);
222 greybus_set_drvdata(bundle
, gbmodule
);
224 dai
->data_cport
= connection
->intf_cport_id
;
225 dai
->connection
= connection
;
226 list_add(&dai
->list
, &gbmodule
->data_list
);
232 * This is the basic hook get things initialized and registered w/ gb
235 static int gb_audio_probe(struct gb_bundle
*bundle
,
236 const struct greybus_bundle_id
*id
)
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
;
244 struct gb_audio_topology
*topology
;
246 /* There should be at least one Management and one Data cport */
247 if (bundle
->num_cports
< 2)
251 * There can be only one Management connection and any number of data
254 gbmodule
= devm_kzalloc(dev
, sizeof(*gbmodule
), GFP_KERNEL
);
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
);
264 snprintf(gbmodule
->name
, NAME_SIZE
, "%s.%s", dev
->driver
->name
,
266 greybus_set_drvdata(bundle
, gbmodule
);
268 /* Create all connections */
269 for (i
= 0; i
< bundle
->num_cports
; i
++) {
270 cport_desc
= &bundle
->cport_desc
[i
];
272 switch (cport_desc
->protocol_id
) {
273 case GREYBUS_PROTOCOL_AUDIO_MGMT
:
274 ret
= gb_audio_add_mgmt_connection(gbmodule
, cport_desc
,
277 goto destroy_connections
;
279 case GREYBUS_PROTOCOL_AUDIO_DATA
:
280 ret
= gb_audio_add_data_connection(gbmodule
, cport_desc
,
283 goto destroy_connections
;
286 dev_err(dev
, "Unsupported protocol: 0x%02x\n",
287 cport_desc
->protocol_id
);
289 goto destroy_connections
;
293 /* There must be a management cport */
294 if (!gbmodule
->mgmt_connection
) {
296 dev_err(dev
, "Missing management connection\n");
297 goto destroy_connections
;
300 /* Initialize management connection */
301 ret
= gb_connection_enable(gbmodule
->mgmt_connection
);
303 dev_err(dev
, "%d: Error while enabling mgmt connection\n", ret
);
304 goto destroy_connections
;
306 gbmodule
->dev_id
= gbmodule
->mgmt_connection
->intf
->interface_id
;
309 * FIXME: malloc for topology happens via audio_gb driver
310 * should be done within codec driver itself
312 ret
= gb_audio_gb_get_topology(gbmodule
->mgmt_connection
, &topology
);
314 dev_err(dev
, "%d:Error while fetching topology\n", ret
);
315 goto disable_connection
;
318 /* process topology data */
319 ret
= gbaudio_tplg_parse_data(gbmodule
, topology
);
321 dev_err(dev
, "%d:Error while parsing topology data\n",
325 gbmodule
->topology
= topology
;
327 /* Initialize data connections */
328 list_for_each_entry(dai
, &gbmodule
->data_list
, list
) {
329 ret
= gb_connection_enable(dai
->connection
);
332 "%d:Error while enabling %d:data connection\n",
333 ret
, dai
->data_cport
);
334 goto disable_data_connection
;
338 /* register module with gbcodec */
339 ret
= gbaudio_register_module(gbmodule
);
341 goto disable_data_connection
;
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
);
354 dev_dbg(dev
, "Add GB Audio device:%s\n", gbmodule
->name
);
356 gb_pm_runtime_put_autosuspend(bundle
);
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
;
370 gb_connection_disable(gbmodule
->mgmt_connection
);
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
);
379 if (gbmodule
->mgmt_connection
)
380 gb_connection_destroy(gbmodule
->mgmt_connection
);
382 devm_kfree(dev
, gbmodule
);
387 static void gb_audio_disconnect(struct gb_bundle
*bundle
)
389 struct gbaudio_module_info
*gbmodule
= greybus_get_drvdata(bundle
);
390 struct gbaudio_data_connection
*dai
, *_dai
;
392 gb_pm_runtime_get_sync(bundle
);
394 /* cleanup module related resources first */
395 gbaudio_unregister_module(gbmodule
);
397 /* inform uevent to above layers */
398 gb_audio_manager_remove(gbmodule
->manager_id
);
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
);
410 gb_connection_destroy(gbmodule
->mgmt_connection
);
411 gbmodule
->mgmt_connection
= NULL
;
413 devm_kfree(&bundle
->dev
, gbmodule
);
416 static const struct greybus_bundle_id gb_audio_id_table
[] = {
417 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO
) },
420 MODULE_DEVICE_TABLE(greybus
, gb_audio_id_table
);
423 static int gb_audio_suspend(struct device
*dev
)
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
;
429 list_for_each_entry(dai
, &gbmodule
->data_list
, list
)
430 gb_connection_disable(dai
->connection
);
432 gb_connection_disable(gbmodule
->mgmt_connection
);
437 static int gb_audio_resume(struct device
*dev
)
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
;
444 ret
= gb_connection_enable(gbmodule
->mgmt_connection
);
446 dev_err(dev
, "%d:Error while enabling mgmt connection\n", ret
);
450 list_for_each_entry(dai
, &gbmodule
->data_list
, list
) {
451 ret
= gb_connection_enable(dai
->connection
);
454 "%d:Error while enabling %d:data connection\n",
455 ret
, dai
->data_cport
);
464 static const struct dev_pm_ops gb_audio_pm_ops
= {
465 SET_RUNTIME_PM_OPS(gb_audio_suspend
, gb_audio_resume
, NULL
)
468 static struct greybus_driver gb_audio_driver
= {
470 .probe
= gb_audio_probe
,
471 .disconnect
= gb_audio_disconnect
,
472 .id_table
= gb_audio_id_table
,
473 .driver
.pm
= &gb_audio_pm_ops
,
475 module_greybus_driver(gb_audio_driver
);
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");