diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/soc/mid-x86/sst_platform.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/soc/mid-x86/sst_platform.c')
-rw-r--r-- | sound/soc/mid-x86/sst_platform.c | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c new file mode 100644 index 000000000000..5a946b4115a2 --- /dev/null +++ b/sound/soc/mid-x86/sst_platform.c | |||
@@ -0,0 +1,486 @@ | |||
1 | /* | ||
2 | * sst_platform.c - Intel MID Platform driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | * | ||
25 | */ | ||
26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
27 | |||
28 | #include <linux/slab.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include "../../../drivers/staging/intel_sst/intel_sst_ioctl.h" | ||
35 | #include "../../../drivers/staging/intel_sst/intel_sst.h" | ||
36 | #include "sst_platform.h" | ||
37 | |||
38 | static struct snd_pcm_hardware sst_platform_pcm_hw = { | ||
39 | .info = (SNDRV_PCM_INFO_INTERLEAVED | | ||
40 | SNDRV_PCM_INFO_DOUBLE | | ||
41 | SNDRV_PCM_INFO_PAUSE | | ||
42 | SNDRV_PCM_INFO_RESUME | | ||
43 | SNDRV_PCM_INFO_MMAP| | ||
44 | SNDRV_PCM_INFO_MMAP_VALID | | ||
45 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
46 | SNDRV_PCM_INFO_SYNC_START), | ||
47 | .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 | | ||
48 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 | | ||
49 | SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32), | ||
50 | .rates = (SNDRV_PCM_RATE_8000| | ||
51 | SNDRV_PCM_RATE_44100 | | ||
52 | SNDRV_PCM_RATE_48000), | ||
53 | .rate_min = SST_MIN_RATE, | ||
54 | .rate_max = SST_MAX_RATE, | ||
55 | .channels_min = SST_MIN_CHANNEL, | ||
56 | .channels_max = SST_MAX_CHANNEL, | ||
57 | .buffer_bytes_max = SST_MAX_BUFFER, | ||
58 | .period_bytes_min = SST_MIN_PERIOD_BYTES, | ||
59 | .period_bytes_max = SST_MAX_PERIOD_BYTES, | ||
60 | .periods_min = SST_MIN_PERIODS, | ||
61 | .periods_max = SST_MAX_PERIODS, | ||
62 | .fifo_size = SST_FIFO_SIZE, | ||
63 | }; | ||
64 | |||
65 | /* MFLD - MSIC */ | ||
66 | struct snd_soc_dai_driver sst_platform_dai[] = { | ||
67 | { | ||
68 | .name = "Headset-cpu-dai", | ||
69 | .id = 0, | ||
70 | .playback = { | ||
71 | .channels_min = SST_STEREO, | ||
72 | .channels_max = SST_STEREO, | ||
73 | .rates = SNDRV_PCM_RATE_48000, | ||
74 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
75 | }, | ||
76 | .capture = { | ||
77 | .channels_min = 1, | ||
78 | .channels_max = 5, | ||
79 | .rates = SNDRV_PCM_RATE_48000, | ||
80 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
81 | }, | ||
82 | }, | ||
83 | { | ||
84 | .name = "Speaker-cpu-dai", | ||
85 | .id = 1, | ||
86 | .playback = { | ||
87 | .channels_min = SST_MONO, | ||
88 | .channels_max = SST_STEREO, | ||
89 | .rates = SNDRV_PCM_RATE_48000, | ||
90 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
91 | }, | ||
92 | }, | ||
93 | { | ||
94 | .name = "Vibra1-cpu-dai", | ||
95 | .id = 2, | ||
96 | .playback = { | ||
97 | .channels_min = SST_MONO, | ||
98 | .channels_max = SST_MONO, | ||
99 | .rates = SNDRV_PCM_RATE_48000, | ||
100 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
101 | }, | ||
102 | }, | ||
103 | { | ||
104 | .name = "Vibra2-cpu-dai", | ||
105 | .id = 3, | ||
106 | .playback = { | ||
107 | .channels_min = SST_MONO, | ||
108 | .channels_max = SST_STEREO, | ||
109 | .rates = SNDRV_PCM_RATE_48000, | ||
110 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
111 | }, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | /* helper functions */ | ||
116 | static inline void sst_set_stream_status(struct sst_runtime_stream *stream, | ||
117 | int state) | ||
118 | { | ||
119 | unsigned long flags; | ||
120 | spin_lock_irqsave(&stream->status_lock, flags); | ||
121 | stream->stream_status = state; | ||
122 | spin_unlock_irqrestore(&stream->status_lock, flags); | ||
123 | } | ||
124 | |||
125 | static inline int sst_get_stream_status(struct sst_runtime_stream *stream) | ||
126 | { | ||
127 | int state; | ||
128 | unsigned long flags; | ||
129 | |||
130 | spin_lock_irqsave(&stream->status_lock, flags); | ||
131 | state = stream->stream_status; | ||
132 | spin_unlock_irqrestore(&stream->status_lock, flags); | ||
133 | return state; | ||
134 | } | ||
135 | |||
136 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, | ||
137 | struct snd_sst_stream_params *param) | ||
138 | { | ||
139 | |||
140 | param->uc.pcm_params.codec = SST_CODEC_TYPE_PCM; | ||
141 | param->uc.pcm_params.num_chan = (u8) substream->runtime->channels; | ||
142 | param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits; | ||
143 | param->uc.pcm_params.reserved = 0; | ||
144 | param->uc.pcm_params.sfreq = substream->runtime->rate; | ||
145 | param->uc.pcm_params.ring_buffer_size = | ||
146 | snd_pcm_lib_buffer_bytes(substream); | ||
147 | param->uc.pcm_params.period_count = substream->runtime->period_size; | ||
148 | param->uc.pcm_params.ring_buffer_addr = | ||
149 | virt_to_phys(substream->dma_buffer.area); | ||
150 | pr_debug("period_cnt = %d\n", param->uc.pcm_params.period_count); | ||
151 | pr_debug("sfreq= %d, wd_sz = %d\n", | ||
152 | param->uc.pcm_params.sfreq, param->uc.pcm_params.pcm_wd_sz); | ||
153 | } | ||
154 | |||
155 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream) | ||
156 | { | ||
157 | struct sst_runtime_stream *stream = | ||
158 | substream->runtime->private_data; | ||
159 | struct snd_sst_stream_params param = {{{0,},},}; | ||
160 | struct snd_sst_params str_params = {0}; | ||
161 | int ret_val; | ||
162 | |||
163 | /* set codec params and inform SST driver the same */ | ||
164 | sst_fill_pcm_params(substream, ¶m); | ||
165 | substream->runtime->dma_area = substream->dma_buffer.area; | ||
166 | str_params.sparams = param; | ||
167 | str_params.codec = param.uc.pcm_params.codec; | ||
168 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
169 | str_params.ops = STREAM_OPS_PLAYBACK; | ||
170 | str_params.device_type = substream->pcm->device + 1; | ||
171 | pr_debug("Playbck stream,Device %d\n", | ||
172 | substream->pcm->device); | ||
173 | } else { | ||
174 | str_params.ops = STREAM_OPS_CAPTURE; | ||
175 | str_params.device_type = SND_SST_DEVICE_CAPTURE; | ||
176 | pr_debug("Capture stream,Device %d\n", | ||
177 | substream->pcm->device); | ||
178 | } | ||
179 | ret_val = stream->sstdrv_ops->pcm_control->open(&str_params); | ||
180 | pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); | ||
181 | if (ret_val < 0) | ||
182 | return ret_val; | ||
183 | |||
184 | stream->stream_info.str_id = ret_val; | ||
185 | pr_debug("str id : %d\n", stream->stream_info.str_id); | ||
186 | return ret_val; | ||
187 | } | ||
188 | |||
189 | static void sst_period_elapsed(void *mad_substream) | ||
190 | { | ||
191 | struct snd_pcm_substream *substream = mad_substream; | ||
192 | struct sst_runtime_stream *stream; | ||
193 | int status; | ||
194 | |||
195 | if (!substream || !substream->runtime) | ||
196 | return; | ||
197 | stream = substream->runtime->private_data; | ||
198 | if (!stream) | ||
199 | return; | ||
200 | status = sst_get_stream_status(stream); | ||
201 | if (status != SST_PLATFORM_RUNNING) | ||
202 | return; | ||
203 | snd_pcm_period_elapsed(substream); | ||
204 | } | ||
205 | |||
206 | static int sst_platform_init_stream(struct snd_pcm_substream *substream) | ||
207 | { | ||
208 | struct sst_runtime_stream *stream = | ||
209 | substream->runtime->private_data; | ||
210 | int ret_val; | ||
211 | |||
212 | pr_debug("setting buffer ptr param\n"); | ||
213 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | ||
214 | stream->stream_info.period_elapsed = sst_period_elapsed; | ||
215 | stream->stream_info.mad_substream = substream; | ||
216 | stream->stream_info.buffer_ptr = 0; | ||
217 | stream->stream_info.sfreq = substream->runtime->rate; | ||
218 | ret_val = stream->sstdrv_ops->pcm_control->device_control( | ||
219 | SST_SND_STREAM_INIT, &stream->stream_info); | ||
220 | if (ret_val) | ||
221 | pr_err("control_set ret error %d\n", ret_val); | ||
222 | return ret_val; | ||
223 | |||
224 | } | ||
225 | /* end -- helper functions */ | ||
226 | |||
227 | static int sst_platform_open(struct snd_pcm_substream *substream) | ||
228 | { | ||
229 | struct snd_pcm_runtime *runtime; | ||
230 | struct sst_runtime_stream *stream; | ||
231 | int ret_val = 0; | ||
232 | |||
233 | pr_debug("sst_platform_open called\n"); | ||
234 | runtime = substream->runtime; | ||
235 | runtime->hw = sst_platform_pcm_hw; | ||
236 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
237 | if (!stream) | ||
238 | return -ENOMEM; | ||
239 | spin_lock_init(&stream->status_lock); | ||
240 | stream->stream_info.str_id = 0; | ||
241 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | ||
242 | stream->stream_info.mad_substream = substream; | ||
243 | /* allocate memory for SST API set */ | ||
244 | stream->sstdrv_ops = kzalloc(sizeof(*stream->sstdrv_ops), | ||
245 | GFP_KERNEL); | ||
246 | if (!stream->sstdrv_ops) { | ||
247 | pr_err("sst: mem allocation for ops fail\n"); | ||
248 | kfree(stream); | ||
249 | return -ENOMEM; | ||
250 | } | ||
251 | stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID; | ||
252 | stream->sstdrv_ops->module_name = SST_CARD_NAMES; | ||
253 | /* registering with SST driver to get access to SST APIs to use */ | ||
254 | ret_val = register_sst_card(stream->sstdrv_ops); | ||
255 | if (ret_val) { | ||
256 | pr_err("sst: sst card registration failed\n"); | ||
257 | kfree(stream->sstdrv_ops); | ||
258 | kfree(stream); | ||
259 | return ret_val; | ||
260 | } | ||
261 | runtime->private_data = stream; | ||
262 | return snd_pcm_hw_constraint_integer(runtime, | ||
263 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
264 | } | ||
265 | |||
266 | static int sst_platform_close(struct snd_pcm_substream *substream) | ||
267 | { | ||
268 | struct sst_runtime_stream *stream; | ||
269 | int ret_val = 0, str_id; | ||
270 | |||
271 | pr_debug("sst_platform_close called\n"); | ||
272 | stream = substream->runtime->private_data; | ||
273 | str_id = stream->stream_info.str_id; | ||
274 | if (str_id) | ||
275 | ret_val = stream->sstdrv_ops->pcm_control->close(str_id); | ||
276 | unregister_sst_card(stream->sstdrv_ops); | ||
277 | kfree(stream->sstdrv_ops); | ||
278 | kfree(stream); | ||
279 | return ret_val; | ||
280 | } | ||
281 | |||
282 | static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | ||
283 | { | ||
284 | struct sst_runtime_stream *stream; | ||
285 | int ret_val = 0, str_id; | ||
286 | |||
287 | pr_debug("sst_platform_pcm_prepare called\n"); | ||
288 | stream = substream->runtime->private_data; | ||
289 | str_id = stream->stream_info.str_id; | ||
290 | if (stream->stream_info.str_id) { | ||
291 | ret_val = stream->sstdrv_ops->pcm_control->device_control( | ||
292 | SST_SND_DROP, &str_id); | ||
293 | return ret_val; | ||
294 | } | ||
295 | |||
296 | ret_val = sst_platform_alloc_stream(substream); | ||
297 | if (ret_val < 0) | ||
298 | return ret_val; | ||
299 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), | ||
300 | "%d", stream->stream_info.str_id); | ||
301 | |||
302 | ret_val = sst_platform_init_stream(substream); | ||
303 | if (ret_val) | ||
304 | return ret_val; | ||
305 | substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER; | ||
306 | return ret_val; | ||
307 | } | ||
308 | |||
309 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | ||
310 | int cmd) | ||
311 | { | ||
312 | int ret_val = 0, str_id; | ||
313 | struct sst_runtime_stream *stream; | ||
314 | int str_cmd, status; | ||
315 | |||
316 | pr_debug("sst_platform_pcm_trigger called\n"); | ||
317 | stream = substream->runtime->private_data; | ||
318 | str_id = stream->stream_info.str_id; | ||
319 | switch (cmd) { | ||
320 | case SNDRV_PCM_TRIGGER_START: | ||
321 | pr_debug("sst: Trigger Start\n"); | ||
322 | str_cmd = SST_SND_START; | ||
323 | status = SST_PLATFORM_RUNNING; | ||
324 | stream->stream_info.mad_substream = substream; | ||
325 | break; | ||
326 | case SNDRV_PCM_TRIGGER_STOP: | ||
327 | pr_debug("sst: in stop\n"); | ||
328 | str_cmd = SST_SND_DROP; | ||
329 | status = SST_PLATFORM_DROPPED; | ||
330 | break; | ||
331 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
332 | pr_debug("sst: in pause\n"); | ||
333 | str_cmd = SST_SND_PAUSE; | ||
334 | status = SST_PLATFORM_PAUSED; | ||
335 | break; | ||
336 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
337 | pr_debug("sst: in pause release\n"); | ||
338 | str_cmd = SST_SND_RESUME; | ||
339 | status = SST_PLATFORM_RUNNING; | ||
340 | break; | ||
341 | default: | ||
342 | return -EINVAL; | ||
343 | } | ||
344 | ret_val = stream->sstdrv_ops->pcm_control->device_control(str_cmd, | ||
345 | &str_id); | ||
346 | if (!ret_val) | ||
347 | sst_set_stream_status(stream, status); | ||
348 | |||
349 | return ret_val; | ||
350 | } | ||
351 | |||
352 | |||
353 | static snd_pcm_uframes_t sst_platform_pcm_pointer | ||
354 | (struct snd_pcm_substream *substream) | ||
355 | { | ||
356 | struct sst_runtime_stream *stream; | ||
357 | int ret_val, status; | ||
358 | struct pcm_stream_info *str_info; | ||
359 | |||
360 | stream = substream->runtime->private_data; | ||
361 | status = sst_get_stream_status(stream); | ||
362 | if (status == SST_PLATFORM_INIT) | ||
363 | return 0; | ||
364 | str_info = &stream->stream_info; | ||
365 | ret_val = stream->sstdrv_ops->pcm_control->device_control( | ||
366 | SST_SND_BUFFER_POINTER, str_info); | ||
367 | if (ret_val) { | ||
368 | pr_err("sst: error code = %d\n", ret_val); | ||
369 | return ret_val; | ||
370 | } | ||
371 | return stream->stream_info.buffer_ptr; | ||
372 | } | ||
373 | |||
374 | static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, | ||
375 | struct snd_pcm_hw_params *params) | ||
376 | { | ||
377 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
378 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) | ||
384 | { | ||
385 | return snd_pcm_lib_free_pages(substream); | ||
386 | } | ||
387 | |||
388 | static struct snd_pcm_ops sst_platform_ops = { | ||
389 | .open = sst_platform_open, | ||
390 | .close = sst_platform_close, | ||
391 | .ioctl = snd_pcm_lib_ioctl, | ||
392 | .prepare = sst_platform_pcm_prepare, | ||
393 | .trigger = sst_platform_pcm_trigger, | ||
394 | .pointer = sst_platform_pcm_pointer, | ||
395 | .hw_params = sst_platform_pcm_hw_params, | ||
396 | .hw_free = sst_platform_pcm_hw_free, | ||
397 | }; | ||
398 | |||
399 | static void sst_pcm_free(struct snd_pcm *pcm) | ||
400 | { | ||
401 | pr_debug("sst_pcm_free called\n"); | ||
402 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
403 | } | ||
404 | |||
405 | int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
406 | struct snd_pcm *pcm) | ||
407 | { | ||
408 | int retval = 0; | ||
409 | |||
410 | pr_debug("sst_pcm_new called\n"); | ||
411 | if (dai->driver->playback.channels_min || | ||
412 | dai->driver->capture.channels_min) { | ||
413 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
414 | SNDRV_DMA_TYPE_CONTINUOUS, | ||
415 | snd_dma_continuous_data(GFP_KERNEL), | ||
416 | SST_MIN_BUFFER, SST_MAX_BUFFER); | ||
417 | if (retval) { | ||
418 | pr_err("dma buffer allocationf fail\n"); | ||
419 | return retval; | ||
420 | } | ||
421 | } | ||
422 | return retval; | ||
423 | } | ||
424 | struct snd_soc_platform_driver sst_soc_platform_drv = { | ||
425 | .ops = &sst_platform_ops, | ||
426 | .pcm_new = sst_pcm_new, | ||
427 | .pcm_free = sst_pcm_free, | ||
428 | }; | ||
429 | |||
430 | static int sst_platform_probe(struct platform_device *pdev) | ||
431 | { | ||
432 | int ret; | ||
433 | |||
434 | pr_debug("sst_platform_probe called\n"); | ||
435 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); | ||
436 | if (ret) { | ||
437 | pr_err("registering soc platform failed\n"); | ||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | ret = snd_soc_register_dais(&pdev->dev, | ||
442 | sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); | ||
443 | if (ret) { | ||
444 | pr_err("registering cpu dais failed\n"); | ||
445 | snd_soc_unregister_platform(&pdev->dev); | ||
446 | } | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | static int sst_platform_remove(struct platform_device *pdev) | ||
451 | { | ||
452 | |||
453 | snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai)); | ||
454 | snd_soc_unregister_platform(&pdev->dev); | ||
455 | pr_debug("sst_platform_remove success\n"); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static struct platform_driver sst_platform_driver = { | ||
460 | .driver = { | ||
461 | .name = "sst-platform", | ||
462 | .owner = THIS_MODULE, | ||
463 | }, | ||
464 | .probe = sst_platform_probe, | ||
465 | .remove = sst_platform_remove, | ||
466 | }; | ||
467 | |||
468 | static int __init sst_soc_platform_init(void) | ||
469 | { | ||
470 | pr_debug("sst_soc_platform_init called\n"); | ||
471 | return platform_driver_register(&sst_platform_driver); | ||
472 | } | ||
473 | module_init(sst_soc_platform_init); | ||
474 | |||
475 | static void __exit sst_soc_platform_exit(void) | ||
476 | { | ||
477 | platform_driver_unregister(&sst_platform_driver); | ||
478 | pr_debug("sst_soc_platform_exit success\n"); | ||
479 | } | ||
480 | module_exit(sst_soc_platform_exit); | ||
481 | |||
482 | MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver"); | ||
483 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
484 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
485 | MODULE_LICENSE("GPL v2"); | ||
486 | MODULE_ALIAS("platform:sst-platform"); | ||