GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / staging / most / sound / sound.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * sound.c - Sound component for Mostcore
4  *
5  * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
6  */
7
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10 #include <linux/module.h>
11 #include <linux/printk.h>
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <sound/core.h>
15 #include <sound/pcm.h>
16 #include <sound/pcm_params.h>
17 #include <linux/sched.h>
18 #include <linux/kthread.h>
19 #include <most/core.h>
20
21 #define DRIVER_NAME "sound"
22
23 static struct list_head dev_list;
24 static struct core_component comp;
25
26 /**
27  * struct channel - private structure to keep channel specific data
28  * @substream: stores the substream structure
29  * @iface: interface for which the channel belongs to
30  * @cfg: channel configuration
31  * @card: registered sound card
32  * @list: list for private use
33  * @id: channel index
34  * @period_pos: current period position (ring buffer)
35  * @buffer_pos: current buffer position (ring buffer)
36  * @is_stream_running: identifies whether a stream is running or not
37  * @opened: set when the stream is opened
38  * @playback_task: playback thread
39  * @playback_waitq: waitq used by playback thread
40  */
41 struct channel {
42         struct snd_pcm_substream *substream;
43         struct snd_pcm_hardware pcm_hardware;
44         struct most_interface *iface;
45         struct most_channel_config *cfg;
46         struct snd_card *card;
47         struct list_head list;
48         int id;
49         unsigned int period_pos;
50         unsigned int buffer_pos;
51         bool is_stream_running;
52
53         struct task_struct *playback_task;
54         wait_queue_head_t playback_waitq;
55
56         void (*copy_fn)(void *alsa, void *most, unsigned int bytes);
57 };
58
59 #define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
60                        SNDRV_PCM_INFO_MMAP_VALID | \
61                        SNDRV_PCM_INFO_BATCH | \
62                        SNDRV_PCM_INFO_INTERLEAVED | \
63                        SNDRV_PCM_INFO_BLOCK_TRANSFER)
64
65 #define swap16(val) ( \
66         (((u16)(val) << 8) & (u16)0xFF00) | \
67         (((u16)(val) >> 8) & (u16)0x00FF))
68
69 #define swap32(val) ( \
70         (((u32)(val) << 24) & (u32)0xFF000000) | \
71         (((u32)(val) <<  8) & (u32)0x00FF0000) | \
72         (((u32)(val) >>  8) & (u32)0x0000FF00) | \
73         (((u32)(val) >> 24) & (u32)0x000000FF))
74
75 static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes)
76 {
77         unsigned int i = 0;
78
79         while (i < (bytes / 2)) {
80                 dest[i] = swap16(source[i]);
81                 i++;
82         }
83 }
84
85 static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes)
86 {
87         unsigned int i = 0;
88
89         if (bytes < 2)
90                 return;
91         while (i < bytes - 2) {
92                 dest[i] = source[i + 2];
93                 dest[i + 1] = source[i + 1];
94                 dest[i + 2] = source[i];
95                 i += 3;
96         }
97 }
98
99 static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes)
100 {
101         unsigned int i = 0;
102
103         while (i < bytes / 4) {
104                 dest[i] = swap32(source[i]);
105                 i++;
106         }
107 }
108
109 static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes)
110 {
111         memcpy(most, alsa, bytes);
112 }
113
114 static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes)
115 {
116         swap_copy16(most, alsa, bytes);
117 }
118
119 static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes)
120 {
121         swap_copy24(most, alsa, bytes);
122 }
123
124 static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes)
125 {
126         swap_copy32(most, alsa, bytes);
127 }
128
129 static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes)
130 {
131         memcpy(alsa, most, bytes);
132 }
133
134 static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes)
135 {
136         swap_copy16(alsa, most, bytes);
137 }
138
139 static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes)
140 {
141         swap_copy24(alsa, most, bytes);
142 }
143
144 static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes)
145 {
146         swap_copy32(alsa, most, bytes);
147 }
148
149 /**
150  * get_channel - get pointer to channel
151  * @iface: interface structure
152  * @channel_id: channel ID
153  *
154  * This traverses the channel list and returns the channel matching the
155  * ID and interface.
156  *
157  * Returns pointer to channel on success or NULL otherwise.
158  */
159 static struct channel *get_channel(struct most_interface *iface,
160                                    int channel_id)
161 {
162         struct channel *channel, *tmp;
163
164         list_for_each_entry_safe(channel, tmp, &dev_list, list) {
165                 if ((channel->iface == iface) && (channel->id == channel_id))
166                         return channel;
167         }
168
169         return NULL;
170 }
171
172 /**
173  * copy_data - implements data copying function
174  * @channel: channel
175  * @mbo: MBO from core
176  *
177  * Copy data from/to ring buffer to/from MBO and update the buffer position
178  */
179 static bool copy_data(struct channel *channel, struct mbo *mbo)
180 {
181         struct snd_pcm_runtime *const runtime = channel->substream->runtime;
182         unsigned int const frame_bytes = channel->cfg->subbuffer_size;
183         unsigned int const buffer_size = runtime->buffer_size;
184         unsigned int frames;
185         unsigned int fr0;
186
187         if (channel->cfg->direction & MOST_CH_RX)
188                 frames = mbo->processed_length / frame_bytes;
189         else
190                 frames = mbo->buffer_length / frame_bytes;
191         fr0 = min(buffer_size - channel->buffer_pos, frames);
192
193         channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes,
194                          mbo->virt_address,
195                          fr0 * frame_bytes);
196
197         if (frames > fr0) {
198                 /* wrap around at end of ring buffer */
199                 channel->copy_fn(runtime->dma_area,
200                                  mbo->virt_address + fr0 * frame_bytes,
201                                  (frames - fr0) * frame_bytes);
202         }
203
204         channel->buffer_pos += frames;
205         if (channel->buffer_pos >= buffer_size)
206                 channel->buffer_pos -= buffer_size;
207         channel->period_pos += frames;
208         if (channel->period_pos >= runtime->period_size) {
209                 channel->period_pos -= runtime->period_size;
210                 return true;
211         }
212
213         return false;
214 }
215
216 /**
217  * playback_thread - function implements the playback thread
218  * @data: private data
219  *
220  * Thread which does the playback functionality in a loop. It waits for a free
221  * MBO from mostcore for a particular channel and copy the data from ring buffer
222  * to MBO. Submit the MBO back to mostcore, after copying the data.
223  *
224  * Returns 0 on success or error code otherwise.
225  */
226 static int playback_thread(void *data)
227 {
228         struct channel *const channel = data;
229
230         while (!kthread_should_stop()) {
231                 struct mbo *mbo = NULL;
232                 bool period_elapsed = false;
233
234                 wait_event_interruptible(
235                         channel->playback_waitq,
236                         kthread_should_stop() ||
237                         (channel->is_stream_running &&
238                          (mbo = most_get_mbo(channel->iface, channel->id,
239                                              &comp))));
240                 if (!mbo)
241                         continue;
242
243                 if (channel->is_stream_running)
244                         period_elapsed = copy_data(channel, mbo);
245                 else
246                         memset(mbo->virt_address, 0, mbo->buffer_length);
247
248                 most_submit_mbo(mbo);
249                 if (period_elapsed)
250                         snd_pcm_period_elapsed(channel->substream);
251         }
252
253         return 0;
254 }
255
256 /**
257  * pcm_open - implements open callback function for PCM middle layer
258  * @substream: pointer to ALSA PCM substream
259  *
260  * This is called when a PCM substream is opened. At least, the function should
261  * initialize the runtime->hw record.
262  *
263  * Returns 0 on success or error code otherwise.
264  */
265 static int pcm_open(struct snd_pcm_substream *substream)
266 {
267         struct channel *channel = substream->private_data;
268         struct snd_pcm_runtime *runtime = substream->runtime;
269         struct most_channel_config *cfg = channel->cfg;
270
271         channel->substream = substream;
272
273         if (cfg->direction == MOST_CH_TX) {
274                 channel->playback_task = kthread_run(playback_thread, channel,
275                                                      "most_audio_playback");
276                 if (IS_ERR(channel->playback_task)) {
277                         pr_err("Couldn't start thread\n");
278                         return PTR_ERR(channel->playback_task);
279                 }
280         }
281
282         if (most_start_channel(channel->iface, channel->id, &comp)) {
283                 pr_err("most_start_channel() failed!\n");
284                 if (cfg->direction == MOST_CH_TX)
285                         kthread_stop(channel->playback_task);
286                 return -EBUSY;
287         }
288
289         runtime->hw = channel->pcm_hardware;
290         return 0;
291 }
292
293 /**
294  * pcm_close - implements close callback function for PCM middle layer
295  * @substream: sub-stream pointer
296  *
297  * Obviously, this is called when a PCM substream is closed. Any private
298  * instance for a PCM substream allocated in the open callback will be
299  * released here.
300  *
301  * Returns 0 on success or error code otherwise.
302  */
303 static int pcm_close(struct snd_pcm_substream *substream)
304 {
305         struct channel *channel = substream->private_data;
306
307         if (channel->cfg->direction == MOST_CH_TX)
308                 kthread_stop(channel->playback_task);
309         most_stop_channel(channel->iface, channel->id, &comp);
310
311         return 0;
312 }
313
314 /**
315  * pcm_hw_params - implements hw_params callback function for PCM middle layer
316  * @substream: sub-stream pointer
317  * @hw_params: contains the hardware parameters set by the application
318  *
319  * This is called when the hardware parameters is set by the application, that
320  * is, once when the buffer size, the period size, the format, etc. are defined
321  * for the PCM substream. Many hardware setups should be done is this callback,
322  * including the allocation of buffers.
323  *
324  * Returns 0 on success or error code otherwise.
325  */
326 static int pcm_hw_params(struct snd_pcm_substream *substream,
327                          struct snd_pcm_hw_params *hw_params)
328 {
329         struct channel *channel = substream->private_data;
330
331         if ((params_channels(hw_params) > channel->pcm_hardware.channels_max) ||
332             (params_channels(hw_params) < channel->pcm_hardware.channels_min)) {
333                 pr_err("Requested number of channels not supported.\n");
334                 return -EINVAL;
335         }
336         return snd_pcm_lib_alloc_vmalloc_buffer(substream,
337                                                 params_buffer_bytes(hw_params));
338 }
339
340 /**
341  * pcm_hw_free - implements hw_free callback function for PCM middle layer
342  * @substream: substream pointer
343  *
344  * This is called to release the resources allocated via hw_params.
345  * This function will be always called before the close callback is called.
346  *
347  * Returns 0 on success or error code otherwise.
348  */
349 static int pcm_hw_free(struct snd_pcm_substream *substream)
350 {
351         return snd_pcm_lib_free_vmalloc_buffer(substream);
352 }
353
354 /**
355  * pcm_prepare - implements prepare callback function for PCM middle layer
356  * @substream: substream pointer
357  *
358  * This callback is called when the PCM is "prepared". Format rate, sample rate,
359  * etc., can be set here. This callback can be called many times at each setup.
360  *
361  * Returns 0 on success or error code otherwise.
362  */
363 static int pcm_prepare(struct snd_pcm_substream *substream)
364 {
365         struct channel *channel = substream->private_data;
366         struct snd_pcm_runtime *runtime = substream->runtime;
367         struct most_channel_config *cfg = channel->cfg;
368         int width = snd_pcm_format_physical_width(runtime->format);
369
370         channel->copy_fn = NULL;
371
372         if (cfg->direction == MOST_CH_TX) {
373                 if (snd_pcm_format_big_endian(runtime->format) || width == 8)
374                         channel->copy_fn = alsa_to_most_memcpy;
375                 else if (width == 16)
376                         channel->copy_fn = alsa_to_most_copy16;
377                 else if (width == 24)
378                         channel->copy_fn = alsa_to_most_copy24;
379                 else if (width == 32)
380                         channel->copy_fn = alsa_to_most_copy32;
381         } else {
382                 if (snd_pcm_format_big_endian(runtime->format) || width == 8)
383                         channel->copy_fn = most_to_alsa_memcpy;
384                 else if (width == 16)
385                         channel->copy_fn = most_to_alsa_copy16;
386                 else if (width == 24)
387                         channel->copy_fn = most_to_alsa_copy24;
388                 else if (width == 32)
389                         channel->copy_fn = most_to_alsa_copy32;
390         }
391
392         if (!channel->copy_fn) {
393                 pr_err("unsupported format\n");
394                 return -EINVAL;
395         }
396
397         channel->period_pos = 0;
398         channel->buffer_pos = 0;
399
400         return 0;
401 }
402
403 /**
404  * pcm_trigger - implements trigger callback function for PCM middle layer
405  * @substream: substream pointer
406  * @cmd: action to perform
407  *
408  * This is called when the PCM is started, stopped or paused. The action will be
409  * specified in the second argument, SNDRV_PCM_TRIGGER_XXX
410  *
411  * Returns 0 on success or error code otherwise.
412  */
413 static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
414 {
415         struct channel *channel = substream->private_data;
416
417         switch (cmd) {
418         case SNDRV_PCM_TRIGGER_START:
419                 channel->is_stream_running = true;
420                 wake_up_interruptible(&channel->playback_waitq);
421                 return 0;
422
423         case SNDRV_PCM_TRIGGER_STOP:
424                 channel->is_stream_running = false;
425                 return 0;
426
427         default:
428                 pr_info("%s(), invalid\n", __func__);
429                 return -EINVAL;
430         }
431         return 0;
432 }
433
434 /**
435  * pcm_pointer - implements pointer callback function for PCM middle layer
436  * @substream: substream pointer
437  *
438  * This callback is called when the PCM middle layer inquires the current
439  * hardware position on the buffer. The position must be returned in frames,
440  * ranging from 0 to buffer_size-1.
441  */
442 static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
443 {
444         struct channel *channel = substream->private_data;
445
446         return channel->buffer_pos;
447 }
448
449 /**
450  * Initialization of struct snd_pcm_ops
451  */
452 static const struct snd_pcm_ops pcm_ops = {
453         .open       = pcm_open,
454         .close      = pcm_close,
455         .ioctl      = snd_pcm_lib_ioctl,
456         .hw_params  = pcm_hw_params,
457         .hw_free    = pcm_hw_free,
458         .prepare    = pcm_prepare,
459         .trigger    = pcm_trigger,
460         .pointer    = pcm_pointer,
461         .page       = snd_pcm_lib_get_vmalloc_page,
462 };
463
464 static int split_arg_list(char *buf, char **card_name, u16 *ch_num,
465                           char **sample_res)
466 {
467         char *num;
468         int ret;
469
470         *card_name = strsep(&buf, ".");
471         if (!*card_name) {
472                 pr_err("Missing sound card name\n");
473                 return -EIO;
474         }
475         num = strsep(&buf, "x");
476         if (!num)
477                 goto err;
478         ret = kstrtou16(num, 0, ch_num);
479         if (ret)
480                 goto err;
481         *sample_res = strsep(&buf, ".\n");
482         if (!*sample_res)
483                 goto err;
484         return 0;
485
486 err:
487         pr_err("Bad PCM format\n");
488         return -EIO;
489 }
490
491 static const struct sample_resolution_info {
492         const char *sample_res;
493         int bytes;
494         u64 formats;
495 } sinfo[] = {
496         { "8", 1, SNDRV_PCM_FMTBIT_S8 },
497         { "16", 2, SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE },
498         { "24", 3, SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE },
499         { "32", 4, SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE },
500 };
501
502 static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw,
503                                u16 ch_num, char *sample_res,
504                                struct most_channel_config *cfg)
505 {
506         int i;
507
508         for (i = 0; i < ARRAY_SIZE(sinfo); i++) {
509                 if (!strcmp(sample_res, sinfo[i].sample_res))
510                         goto found;
511         }
512         pr_err("Unsupported PCM format\n");
513         return -EIO;
514
515 found:
516         if (!ch_num) {
517                 pr_err("Bad number of channels\n");
518                 return -EINVAL;
519         }
520
521         if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) {
522                 pr_err("Audio resolution doesn't fit subbuffer size\n");
523                 return -EINVAL;
524         }
525
526         pcm_hw->info = MOST_PCM_INFO;
527         pcm_hw->rates = SNDRV_PCM_RATE_48000;
528         pcm_hw->rate_min = 48000;
529         pcm_hw->rate_max = 48000;
530         pcm_hw->buffer_bytes_max = cfg->num_buffers * cfg->buffer_size;
531         pcm_hw->period_bytes_min = cfg->buffer_size;
532         pcm_hw->period_bytes_max = cfg->buffer_size;
533         pcm_hw->periods_min = 1;
534         pcm_hw->periods_max = cfg->num_buffers;
535         pcm_hw->channels_min = ch_num;
536         pcm_hw->channels_max = ch_num;
537         pcm_hw->formats = sinfo[i].formats;
538         return 0;
539 }
540
541 /**
542  * audio_probe_channel - probe function of the driver module
543  * @iface: pointer to interface instance
544  * @channel_id: channel index/ID
545  * @cfg: pointer to actual channel configuration
546  * @arg_list: string that provides the name of the device to be created in /dev
547  *            plus the desired audio resolution
548  *
549  * Creates sound card, pcm device, sets pcm ops and registers sound card.
550  *
551  * Returns 0 on success or error code otherwise.
552  */
553 static int audio_probe_channel(struct most_interface *iface, int channel_id,
554                                struct most_channel_config *cfg,
555                                char *arg_list)
556 {
557         struct channel *channel;
558         struct snd_card *card;
559         struct snd_pcm *pcm;
560         int playback_count = 0;
561         int capture_count = 0;
562         int ret;
563         int direction;
564         char *card_name;
565         u16 ch_num;
566         char *sample_res;
567
568         if (!iface)
569                 return -EINVAL;
570
571         if (cfg->data_type != MOST_CH_SYNC) {
572                 pr_err("Incompatible channel type\n");
573                 return -EINVAL;
574         }
575
576         if (get_channel(iface, channel_id)) {
577                 pr_err("channel (%s:%d) is already linked\n",
578                        iface->description, channel_id);
579                 return -EINVAL;
580         }
581
582         if (cfg->direction == MOST_CH_TX) {
583                 playback_count = 1;
584                 direction = SNDRV_PCM_STREAM_PLAYBACK;
585         } else {
586                 capture_count = 1;
587                 direction = SNDRV_PCM_STREAM_CAPTURE;
588         }
589
590         ret = split_arg_list(arg_list, &card_name, &ch_num, &sample_res);
591         if (ret < 0)
592                 return ret;
593
594         ret = snd_card_new(&iface->dev, -1, card_name, THIS_MODULE,
595                            sizeof(*channel), &card);
596         if (ret < 0)
597                 return ret;
598
599         channel = card->private_data;
600         channel->card = card;
601         channel->cfg = cfg;
602         channel->iface = iface;
603         channel->id = channel_id;
604         init_waitqueue_head(&channel->playback_waitq);
605
606         ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res,
607                                   cfg);
608         if (ret)
609                 goto err_free_card;
610
611         snprintf(card->driver, sizeof(card->driver), "%s", DRIVER_NAME);
612         snprintf(card->shortname, sizeof(card->shortname), "Microchip MOST:%d",
613                  card->number);
614         snprintf(card->longname, sizeof(card->longname), "%s at %s, ch %d",
615                  card->shortname, iface->description, channel_id);
616
617         ret = snd_pcm_new(card, card_name, 0, playback_count,
618                           capture_count, &pcm);
619         if (ret < 0)
620                 goto err_free_card;
621
622         pcm->private_data = channel;
623
624         snd_pcm_set_ops(pcm, direction, &pcm_ops);
625
626         ret = snd_card_register(card);
627         if (ret < 0)
628                 goto err_free_card;
629
630         list_add_tail(&channel->list, &dev_list);
631
632         return 0;
633
634 err_free_card:
635         snd_card_free(card);
636         return ret;
637 }
638
639 /**
640  * audio_disconnect_channel - function to disconnect a channel
641  * @iface: pointer to interface instance
642  * @channel_id: channel index
643  *
644  * This frees allocated memory and removes the sound card from ALSA
645  *
646  * Returns 0 on success or error code otherwise.
647  */
648 static int audio_disconnect_channel(struct most_interface *iface,
649                                     int channel_id)
650 {
651         struct channel *channel;
652
653         channel = get_channel(iface, channel_id);
654         if (!channel) {
655                 pr_err("sound_disconnect_channel(), invalid channel %d\n",
656                        channel_id);
657                 return -EINVAL;
658         }
659
660         list_del(&channel->list);
661         snd_card_free(channel->card);
662
663         return 0;
664 }
665
666 /**
667  * audio_rx_completion - completion handler for rx channels
668  * @mbo: pointer to buffer object that has completed
669  *
670  * This searches for the channel this MBO belongs to and copy the data from MBO
671  * to ring buffer
672  *
673  * Returns 0 on success or error code otherwise.
674  */
675 static int audio_rx_completion(struct mbo *mbo)
676 {
677         struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id);
678         bool period_elapsed = false;
679
680         if (!channel) {
681                 pr_err("sound_rx_completion(), invalid channel %d\n",
682                        mbo->hdm_channel_id);
683                 return -EINVAL;
684         }
685
686         if (channel->is_stream_running)
687                 period_elapsed = copy_data(channel, mbo);
688
689         most_put_mbo(mbo);
690
691         if (period_elapsed)
692                 snd_pcm_period_elapsed(channel->substream);
693
694         return 0;
695 }
696
697 /**
698  * audio_tx_completion - completion handler for tx channels
699  * @iface: pointer to interface instance
700  * @channel_id: channel index/ID
701  *
702  * This searches the channel that belongs to this combination of interface
703  * pointer and channel ID and wakes a process sitting in the wait queue of
704  * this channel.
705  *
706  * Returns 0 on success or error code otherwise.
707  */
708 static int audio_tx_completion(struct most_interface *iface, int channel_id)
709 {
710         struct channel *channel = get_channel(iface, channel_id);
711
712         if (!channel) {
713                 pr_err("sound_tx_completion(), invalid channel %d\n",
714                        channel_id);
715                 return -EINVAL;
716         }
717
718         wake_up_interruptible(&channel->playback_waitq);
719
720         return 0;
721 }
722
723 /**
724  * Initialization of the struct core_component
725  */
726 static struct core_component comp = {
727         .name = DRIVER_NAME,
728         .probe_channel = audio_probe_channel,
729         .disconnect_channel = audio_disconnect_channel,
730         .rx_completion = audio_rx_completion,
731         .tx_completion = audio_tx_completion,
732 };
733
734 static int __init audio_init(void)
735 {
736         pr_info("init()\n");
737
738         INIT_LIST_HEAD(&dev_list);
739
740         return most_register_component(&comp);
741 }
742
743 static void __exit audio_exit(void)
744 {
745         struct channel *channel, *tmp;
746
747         pr_info("exit()\n");
748
749         list_for_each_entry_safe(channel, tmp, &dev_list, list) {
750                 list_del(&channel->list);
751                 snd_card_free(channel->card);
752         }
753
754         most_deregister_component(&comp);
755 }
756
757 module_init(audio_init);
758 module_exit(audio_exit);
759
760 MODULE_LICENSE("GPL");
761 MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>");
762 MODULE_DESCRIPTION("Sound Component Module for Mostcore");