]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/greybus/audio.c
greybus: audio: Add '<' to the print message for short messages
[karo-tx-linux.git] / drivers / staging / greybus / audio.c
1 /*
2  * Greybus audio driver
3  *
4  * Copyright 2015 Google Inc.
5  * Copyright 2015 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/device.h>
12 #include <linux/interrupt.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/workqueue.h>
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20 #include <sound/dmaengine_pcm.h>
21 #include <sound/simple_card.h>
22
23 #include "greybus.h"
24 #include "audio.h"
25
26
27 #define GB_AUDIO_DATA_DRIVER_NAME               "gb_audio_data"
28 #define GB_AUDIO_MGMT_DRIVER_NAME               "gb_audio_mgmt"
29
30 #define RT5647_I2C_ADAPTER_NR                   6
31 #define RT5647_I2C_ADDR                         0x1b
32
33 /*
34  * gb_snd management functions
35  */
36 static DEFINE_SPINLOCK(gb_snd_list_lock);
37 static LIST_HEAD(gb_snd_list);
38 static int device_count;
39
40 static struct gb_snd *gb_find_snd(int bundle_id)
41 {
42         struct gb_snd *tmp, *ret = NULL;
43         unsigned long flags;
44
45         spin_lock_irqsave(&gb_snd_list_lock, flags);
46         list_for_each_entry(tmp, &gb_snd_list, list)
47                 if (tmp->gb_bundle_id == bundle_id) {
48                         ret = tmp;
49                         break;
50                 }
51         spin_unlock_irqrestore(&gb_snd_list_lock, flags);
52         return ret;
53 }
54
55 static struct gb_snd *gb_get_snd(int bundle_id)
56 {
57         struct gb_snd *snd_dev;
58         unsigned long flags;
59
60         snd_dev = gb_find_snd(bundle_id);
61         if (snd_dev)
62                 return snd_dev;
63
64         snd_dev = kzalloc(sizeof(*snd_dev), GFP_KERNEL);
65         if (!snd_dev)
66                 return NULL;
67
68         spin_lock_init(&snd_dev->lock);
69         snd_dev->device_count = device_count++;
70         snd_dev->gb_bundle_id = bundle_id;
71         spin_lock_irqsave(&gb_snd_list_lock, flags);
72         list_add(&snd_dev->list, &gb_snd_list);
73         spin_unlock_irqrestore(&gb_snd_list_lock, flags);
74         return snd_dev;
75 }
76
77 static void gb_free_snd(struct gb_snd *snd)
78 {
79         unsigned long flags;
80
81         spin_lock_irqsave(&gb_snd_list_lock, flags);
82         if (!snd->i2s_tx_connection &&
83                         !snd->mgmt_connection) {
84                 list_del(&snd->list);
85                 spin_unlock_irqrestore(&gb_snd_list_lock, flags);
86                 kfree(snd);
87         } else {
88                 spin_unlock_irqrestore(&gb_snd_list_lock, flags);
89         }
90 }
91
92
93
94
95 /*
96  * This is the ASoC simple card binds the platform codec,
97  * cpu-dai and codec-dai togheter
98  */
99 struct gb_card_info_object {
100         struct asoc_simple_card_info card_info;
101         char codec_name[255];
102         char platform_name[255];
103         char dai_name[255];
104 };
105
106
107 static struct asoc_simple_card_info *setup_card_info(int device_count)
108 {
109         struct gb_card_info_object *obj;
110
111         obj = kzalloc(sizeof(struct gb_card_info_object), GFP_KERNEL);
112         if (!obj)
113                 return NULL;
114
115         obj->card_info.name             = "Greybus Audio Module";
116         obj->card_info.card             = "gb-card";
117         obj->card_info.codec            = obj->codec_name;
118         obj->card_info.platform         = obj->platform_name;
119         obj->card_info.cpu_dai.name     = obj->dai_name;
120 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
121         obj->card_info.cpu_dai.fmt      = SND_SOC_DAIFMT_CBM_CFM;
122 #endif
123 #if USE_RT5645
124         obj->card_info.daifmt           = SND_SOC_DAIFMT_NB_NF |
125                                           SND_SOC_DAIFMT_I2S;
126         sprintf(obj->codec_name, "rt5645.%d-%04x", RT5647_I2C_ADAPTER_NR,
127                 RT5647_I2C_ADDR);
128         obj->card_info.codec_dai.name   = "rt5645-aif1";
129 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
130         obj->card_info.codec_dai.fmt    = SND_SOC_DAIFMT_CBS_CFS;
131 #endif
132         obj->card_info.codec_dai.sysclk = 12288000;
133 #else
134         sprintf(obj->codec_name, "spdif-dit");
135         obj->card_info.codec_dai.name = "dit-hifi";
136 #endif
137         sprintf(obj->platform_name, "gb-pcm-audio.%i", device_count);
138         sprintf(obj->dai_name, "gb-dai-audio.%i", device_count);
139
140         return &obj->card_info;
141 }
142
143 static void free_card_info(struct asoc_simple_card_info *ci)
144 {
145         struct gb_card_info_object *obj;
146
147         obj = container_of(ci, struct gb_card_info_object, card_info);
148         kfree(obj);
149 }
150
151
152 /*
153  * XXX this is sort of cruddy but I get warnings if
154  * we don't have dev.release handler set.
155  */
156 static void default_release(struct device *dev)
157 {
158 }
159
160 /*
161  * GB connection hooks
162  */
163 static int gb_i2s_transmitter_connection_init(struct gb_connection *connection)
164 {
165         struct gb_snd *snd_dev;
166         struct platform_device *codec, *dai;
167         struct asoc_simple_card_info *simple_card;
168 #if USE_RT5645
169         struct i2c_board_info rt5647_info;
170         struct i2c_adapter *i2c_adap;
171 #endif
172         unsigned long flags;
173         int ret;
174
175         snd_dev = gb_get_snd(connection->bundle->id);
176         if (!snd_dev)
177                 return -ENOMEM;
178
179         codec = platform_device_register_simple("spdif-dit", -1, NULL, 0);
180         if (!codec) {
181                 ret = -ENOMEM;
182                 goto out;
183         }
184
185         dai = platform_device_register_simple("gb-pcm-audio", snd_dev->device_count, NULL, 0);
186         if (!dai) {
187                 ret = -ENOMEM;
188                 goto out;
189         }
190
191         simple_card = setup_card_info(snd_dev->device_count);
192         if (!simple_card) {
193                 ret = -ENOMEM;
194                 goto out;
195         }
196
197         spin_lock_irqsave(&snd_dev->lock, flags);
198         snd_dev->card.name = "asoc-simple-card";
199         snd_dev->card.id = snd_dev->device_count;
200         snd_dev->card.dev.release = default_release; /* XXX - suspicious */
201
202         snd_dev->cpu_dai.name = "gb-dai-audio";
203         snd_dev->cpu_dai.id = snd_dev->device_count;
204         snd_dev->cpu_dai.dev.release = default_release; /* XXX - suspicious */
205
206
207         snd_dev->simple_card_info = simple_card;
208         snd_dev->card.dev.platform_data = simple_card;
209
210         snd_dev->codec = codec;
211         snd_dev->i2s_tx_connection = connection;
212         snd_dev->cpu_dai.dev.platform_data = snd_dev;
213         snd_dev->i2s_tx_connection->private = snd_dev;
214         spin_unlock_irqrestore(&snd_dev->lock, flags);
215
216         ret = platform_device_register(&snd_dev->cpu_dai);
217         if (ret) {
218                 pr_err("cpu_dai platform_device register failed\n");
219                 goto out_dai;
220         }
221
222         ret = platform_device_register(&snd_dev->card);
223         if (ret) {
224                 pr_err("card platform_device register failed\n");
225                 goto out_card;
226         }
227
228         ret = gb_i2s_data_get_version(connection);
229         if (ret) {
230                 pr_err("i2s data get_version() failed: %d\n", ret);
231                 goto out_get_ver;
232         }
233
234 #if USE_RT5645
235         rt5647_info.addr = RT5647_I2C_ADDR;
236         strlcpy(rt5647_info.type, "rt5647", I2C_NAME_SIZE);
237
238         i2c_adap = i2c_get_adapter(RT5647_I2C_ADAPTER_NR);
239         if (!i2c_adap) {
240                 pr_err("codec unavailable\n");
241                 ret = -ENODEV;
242                 goto out_get_ver;
243         }
244
245         snd_dev->rt5647 = i2c_new_device(i2c_adap, &rt5647_info);
246         if (!snd_dev->rt5647) {
247                 pr_err("can't create rt5647 i2c device\n");
248                 goto out_get_ver;
249         }
250 #endif
251
252         return 0;
253
254 out_get_ver:
255         platform_device_unregister(&snd_dev->card);
256 out_card:
257         platform_device_unregister(&snd_dev->cpu_dai);
258 out_dai:
259         platform_device_unregister(codec);
260 out:
261         gb_free_snd(snd_dev);
262         return ret;
263 }
264
265 static void gb_i2s_transmitter_connection_exit(struct gb_connection *connection)
266 {
267         struct gb_snd *snd_dev;
268
269         snd_dev = (struct gb_snd *)connection->private;
270
271 #if USE_RT5645
272         i2c_unregister_device(snd_dev->rt5647);
273 #endif
274
275         platform_device_unregister(&snd_dev->card);
276         platform_device_unregister(&snd_dev->cpu_dai);
277         platform_device_unregister(snd_dev->codec);
278
279         free_card_info(snd_dev->simple_card_info);
280         snd_dev->i2s_tx_connection = NULL;
281         gb_free_snd(snd_dev);
282 }
283
284 static int gb_i2s_mgmt_connection_init(struct gb_connection *connection)
285 {
286         struct gb_snd *snd_dev;
287         unsigned long flags;
288         int ret;
289
290         snd_dev = gb_get_snd(connection->bundle->id);
291         if (!snd_dev)
292                 return -ENOMEM;
293
294         spin_lock_irqsave(&snd_dev->lock, flags);
295         snd_dev->mgmt_connection = connection;
296         connection->private = snd_dev;
297         spin_unlock_irqrestore(&snd_dev->lock, flags);
298
299         ret = gb_i2s_mgmt_get_version(connection);
300         if (ret) {
301                 pr_err("i2s mgmt get_version() failed: %d\n", ret);
302                 goto err_free_snd_dev;
303         }
304
305         ret = gb_i2s_mgmt_get_cfgs(snd_dev, connection);
306         if (ret) {
307                 pr_err("can't get i2s configurations: %d\n", ret);
308                 goto err_free_snd_dev;
309         }
310
311         ret = gb_i2s_mgmt_set_samples_per_message(snd_dev->mgmt_connection,
312                                                   CONFIG_SAMPLES_PER_MSG);
313         if (ret) {
314                 pr_err("set_samples_per_msg failed: %d\n", ret);
315                 goto err_free_i2s_configs;
316         }
317
318         snd_dev->send_data_req_buf = kzalloc(SEND_DATA_BUF_LEN, GFP_KERNEL);
319
320         if (!snd_dev->send_data_req_buf) {
321                 ret = -ENOMEM;
322                 goto err_free_i2s_configs;
323         }
324
325         return 0;
326
327 err_free_i2s_configs:
328         gb_i2s_mgmt_free_cfgs(snd_dev);
329 err_free_snd_dev:
330         gb_free_snd(snd_dev);
331         return ret;
332 }
333
334 static void gb_i2s_mgmt_connection_exit(struct gb_connection *connection)
335 {
336         struct gb_snd *snd_dev = (struct gb_snd *)connection->private;
337
338         gb_i2s_mgmt_free_cfgs(snd_dev);
339
340         kfree(snd_dev->send_data_req_buf);
341         snd_dev->send_data_req_buf = NULL;
342
343         snd_dev->mgmt_connection = NULL;
344         gb_free_snd(snd_dev);
345 }
346
347 static int gb_i2s_mgmt_report_event_recv(u8 type, struct gb_operation *op)
348 {
349         struct gb_connection *connection = op->connection;
350         struct gb_i2s_mgmt_report_event_request *req = op->request->payload;
351         char *event_name;
352
353         if (type != GB_I2S_MGMT_TYPE_REPORT_EVENT) {
354                 dev_err(&connection->dev, "Invalid request type: %d\n",
355                         type);
356                 return -EINVAL;
357         }
358
359         if (op->request->payload_size < sizeof(*req)) {
360                 dev_err(&connection->dev, "Short request received (%zu < %zu)\n",
361                         op->request->payload_size, sizeof(*req));
362                 return -EINVAL;
363         }
364
365         switch (req->event) {
366         case GB_I2S_MGMT_EVENT_UNSPECIFIED:
367                 event_name = "UNSPECIFIED";
368                 break;
369         case GB_I2S_MGMT_EVENT_HALT:
370                 /* XXX Should stop streaming now */
371                 event_name = "HALT";
372                 break;
373         case GB_I2S_MGMT_EVENT_INTERNAL_ERROR:
374                 event_name = "INTERNAL_ERROR";
375                 break;
376         case GB_I2S_MGMT_EVENT_PROTOCOL_ERROR:
377                 event_name = "PROTOCOL_ERROR";
378                 break;
379         case GB_I2S_MGMT_EVENT_FAILURE:
380                 event_name = "FAILURE";
381                 break;
382         case GB_I2S_MGMT_EVENT_OUT_OF_SEQUENCE:
383                 event_name = "OUT_OF_SEQUENCE";
384                 break;
385         case GB_I2S_MGMT_EVENT_UNDERRUN:
386                 event_name = "UNDERRUN";
387                 break;
388         case GB_I2S_MGMT_EVENT_OVERRUN:
389                 event_name = "OVERRUN";
390                 break;
391         case GB_I2S_MGMT_EVENT_CLOCKING:
392                 event_name = "CLOCKING";
393                 break;
394         case GB_I2S_MGMT_EVENT_DATA_LEN:
395                 event_name = "DATA_LEN";
396                 break;
397         default:
398                 dev_warn(&connection->dev, "Unknown I2S Event received: %d\n",
399                          req->event);
400                 return -EINVAL;
401         }
402
403         dev_warn(&connection->dev, "I2S Event received: %d - '%s'\n",
404                  req->event, event_name);
405
406         return 0;
407 }
408
409 static struct gb_protocol gb_i2s_receiver_protocol = {
410         .name                   = GB_AUDIO_DATA_DRIVER_NAME,
411         .id                     = GREYBUS_PROTOCOL_I2S_RECEIVER,
412         .major                  = 0,
413         .minor                  = 1,
414         .connection_init        = gb_i2s_transmitter_connection_init,
415         .connection_exit        = gb_i2s_transmitter_connection_exit,
416         .request_recv           = NULL,
417 };
418
419 static struct gb_protocol gb_i2s_mgmt_protocol = {
420         .name                   = GB_AUDIO_MGMT_DRIVER_NAME,
421         .id                     = GREYBUS_PROTOCOL_I2S_MGMT,
422         .major                  = 0,
423         .minor                  = 1,
424         .connection_init        = gb_i2s_mgmt_connection_init,
425         .connection_exit        = gb_i2s_mgmt_connection_exit,
426         .request_recv           = gb_i2s_mgmt_report_event_recv,
427 };
428
429
430 /*
431  * This is the basic hook get things initialized and registered w/ gb
432  */
433
434 int gb_audio_protocol_init(void)
435 {
436         int err;
437
438         err = gb_protocol_register(&gb_i2s_mgmt_protocol);
439         if (err) {
440                 pr_err("Can't register i2s mgmt protocol driver: %d\n", -err);
441                 return err;
442         }
443
444         err = gb_protocol_register(&gb_i2s_receiver_protocol);
445         if (err) {
446                 pr_err("Can't register Audio protocol driver: %d\n", -err);
447                 goto err_unregister_i2s_mgmt;
448         }
449
450         err = platform_driver_register(&gb_audio_plat_driver);
451         if (err) {
452                 pr_err("Can't register platform driver: %d\n", -err);
453                 goto err_unregister_plat;
454         }
455
456         err = platform_driver_register(&gb_audio_pcm_driver);
457         if (err) {
458                 pr_err("Can't register pcm driver: %d\n", -err);
459                 goto err_unregister_pcm;
460         }
461
462         return 0;
463
464 err_unregister_pcm:
465         platform_driver_unregister(&gb_audio_plat_driver);
466 err_unregister_plat:
467         gb_protocol_deregister(&gb_i2s_receiver_protocol);
468 err_unregister_i2s_mgmt:
469         gb_protocol_deregister(&gb_i2s_mgmt_protocol);
470         return err;
471 }
472
473 void gb_audio_protocol_exit(void)
474 {
475         platform_driver_unregister(&gb_audio_pcm_driver);
476         platform_driver_unregister(&gb_audio_plat_driver);
477         gb_protocol_deregister(&gb_i2s_receiver_protocol);
478         gb_protocol_deregister(&gb_i2s_mgmt_protocol);
479 }