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 <linux/module.h>
31 #include <sound/core.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/soc.h>
35 #include "sst_platform.h"
36 
37 static struct sst_device *sst;
38 static DEFINE_MUTEX(sst_lock);
39 
sst_register_dsp(struct sst_device * dev)40 int sst_register_dsp(struct sst_device *dev)
41 {
42 	BUG_ON(!dev);
43 	if (!try_module_get(dev->dev->driver->owner))
44 		return -ENODEV;
45 	mutex_lock(&sst_lock);
46 	if (sst) {
47 		pr_err("we already have a device %s\n", sst->name);
48 		module_put(dev->dev->driver->owner);
49 		mutex_unlock(&sst_lock);
50 		return -EEXIST;
51 	}
52 	pr_debug("registering device %s\n", dev->name);
53 	sst = dev;
54 	mutex_unlock(&sst_lock);
55 	return 0;
56 }
57 EXPORT_SYMBOL_GPL(sst_register_dsp);
58 
sst_unregister_dsp(struct sst_device * dev)59 int sst_unregister_dsp(struct sst_device *dev)
60 {
61 	BUG_ON(!dev);
62 	if (dev != sst)
63 		return -EINVAL;
64 
65 	mutex_lock(&sst_lock);
66 
67 	if (!sst) {
68 		mutex_unlock(&sst_lock);
69 		return -EIO;
70 	}
71 
72 	module_put(sst->dev->driver->owner);
73 	pr_debug("unreg %s\n", sst->name);
74 	sst = NULL;
75 	mutex_unlock(&sst_lock);
76 	return 0;
77 }
78 EXPORT_SYMBOL_GPL(sst_unregister_dsp);
79 
80 static struct snd_pcm_hardware sst_platform_pcm_hw = {
81 	.info =	(SNDRV_PCM_INFO_INTERLEAVED |
82 			SNDRV_PCM_INFO_DOUBLE |
83 			SNDRV_PCM_INFO_PAUSE |
84 			SNDRV_PCM_INFO_RESUME |
85 			SNDRV_PCM_INFO_MMAP|
86 			SNDRV_PCM_INFO_MMAP_VALID |
87 			SNDRV_PCM_INFO_BLOCK_TRANSFER |
88 			SNDRV_PCM_INFO_SYNC_START),
89 	.formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
90 			SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
91 			SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
92 	.rates = (SNDRV_PCM_RATE_8000|
93 			SNDRV_PCM_RATE_44100 |
94 			SNDRV_PCM_RATE_48000),
95 	.rate_min = SST_MIN_RATE,
96 	.rate_max = SST_MAX_RATE,
97 	.channels_min =	SST_MIN_CHANNEL,
98 	.channels_max =	SST_MAX_CHANNEL,
99 	.buffer_bytes_max = SST_MAX_BUFFER,
100 	.period_bytes_min = SST_MIN_PERIOD_BYTES,
101 	.period_bytes_max = SST_MAX_PERIOD_BYTES,
102 	.periods_min = SST_MIN_PERIODS,
103 	.periods_max = SST_MAX_PERIODS,
104 	.fifo_size = SST_FIFO_SIZE,
105 };
106 
107 /* MFLD - MSIC */
108 static struct snd_soc_dai_driver sst_platform_dai[] = {
109 {
110 	.name = "Headset-cpu-dai",
111 	.id = 0,
112 	.playback = {
113 		.channels_min = SST_STEREO,
114 		.channels_max = SST_STEREO,
115 		.rates = SNDRV_PCM_RATE_48000,
116 		.formats = SNDRV_PCM_FMTBIT_S24_LE,
117 	},
118 	.capture = {
119 		.channels_min = 1,
120 		.channels_max = 5,
121 		.rates = SNDRV_PCM_RATE_48000,
122 		.formats = SNDRV_PCM_FMTBIT_S24_LE,
123 	},
124 },
125 {
126 	.name = "Speaker-cpu-dai",
127 	.id = 1,
128 	.playback = {
129 		.channels_min = SST_MONO,
130 		.channels_max = SST_STEREO,
131 		.rates = SNDRV_PCM_RATE_48000,
132 		.formats = SNDRV_PCM_FMTBIT_S24_LE,
133 	},
134 },
135 {
136 	.name = "Vibra1-cpu-dai",
137 	.id = 2,
138 	.playback = {
139 		.channels_min = SST_MONO,
140 		.channels_max = SST_MONO,
141 		.rates = SNDRV_PCM_RATE_48000,
142 		.formats = SNDRV_PCM_FMTBIT_S24_LE,
143 	},
144 },
145 {
146 	.name = "Vibra2-cpu-dai",
147 	.id = 3,
148 	.playback = {
149 		.channels_min = SST_MONO,
150 		.channels_max = SST_STEREO,
151 		.rates = SNDRV_PCM_RATE_48000,
152 		.formats = SNDRV_PCM_FMTBIT_S24_LE,
153 	},
154 },
155 };
156 
157 /* helper functions */
sst_set_stream_status(struct sst_runtime_stream * stream,int state)158 static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
159 					int state)
160 {
161 	unsigned long flags;
162 	spin_lock_irqsave(&stream->status_lock, flags);
163 	stream->stream_status = state;
164 	spin_unlock_irqrestore(&stream->status_lock, flags);
165 }
166 
sst_get_stream_status(struct sst_runtime_stream * stream)167 static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
168 {
169 	int state;
170 	unsigned long flags;
171 
172 	spin_lock_irqsave(&stream->status_lock, flags);
173 	state = stream->stream_status;
174 	spin_unlock_irqrestore(&stream->status_lock, flags);
175 	return state;
176 }
177 
sst_fill_pcm_params(struct snd_pcm_substream * substream,struct sst_pcm_params * param)178 static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
179 				struct sst_pcm_params *param)
180 {
181 
182 	param->codec = SST_CODEC_TYPE_PCM;
183 	param->num_chan = (u8) substream->runtime->channels;
184 	param->pcm_wd_sz = substream->runtime->sample_bits;
185 	param->reserved = 0;
186 	param->sfreq = substream->runtime->rate;
187 	param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream);
188 	param->period_count = substream->runtime->period_size;
189 	param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area);
190 	pr_debug("period_cnt = %d\n", param->period_count);
191 	pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz);
192 }
193 
sst_platform_alloc_stream(struct snd_pcm_substream * substream)194 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
195 {
196 	struct sst_runtime_stream *stream =
197 			substream->runtime->private_data;
198 	struct sst_pcm_params param = {0};
199 	struct sst_stream_params str_params = {0};
200 	int ret_val;
201 
202 	/* set codec params and inform SST driver the same */
203 	sst_fill_pcm_params(substream, &param);
204 	substream->runtime->dma_area = substream->dma_buffer.area;
205 	str_params.sparams = param;
206 	str_params.codec =  param.codec;
207 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
208 		str_params.ops = STREAM_OPS_PLAYBACK;
209 		str_params.device_type = substream->pcm->device + 1;
210 		pr_debug("Playbck stream,Device %d\n",
211 					substream->pcm->device);
212 	} else {
213 		str_params.ops = STREAM_OPS_CAPTURE;
214 		str_params.device_type = SND_SST_DEVICE_CAPTURE;
215 		pr_debug("Capture stream,Device %d\n",
216 					substream->pcm->device);
217 	}
218 	ret_val = stream->ops->open(&str_params);
219 	pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
220 	if (ret_val < 0)
221 		return ret_val;
222 
223 	stream->stream_info.str_id = ret_val;
224 	pr_debug("str id :  %d\n", stream->stream_info.str_id);
225 	return ret_val;
226 }
227 
sst_period_elapsed(void * mad_substream)228 static void sst_period_elapsed(void *mad_substream)
229 {
230 	struct snd_pcm_substream *substream = mad_substream;
231 	struct sst_runtime_stream *stream;
232 	int status;
233 
234 	if (!substream || !substream->runtime)
235 		return;
236 	stream = substream->runtime->private_data;
237 	if (!stream)
238 		return;
239 	status = sst_get_stream_status(stream);
240 	if (status != SST_PLATFORM_RUNNING)
241 		return;
242 	snd_pcm_period_elapsed(substream);
243 }
244 
sst_platform_init_stream(struct snd_pcm_substream * substream)245 static int sst_platform_init_stream(struct snd_pcm_substream *substream)
246 {
247 	struct sst_runtime_stream *stream =
248 			substream->runtime->private_data;
249 	int ret_val;
250 
251 	pr_debug("setting buffer ptr param\n");
252 	sst_set_stream_status(stream, SST_PLATFORM_INIT);
253 	stream->stream_info.period_elapsed = sst_period_elapsed;
254 	stream->stream_info.mad_substream = substream;
255 	stream->stream_info.buffer_ptr = 0;
256 	stream->stream_info.sfreq = substream->runtime->rate;
257 	ret_val = stream->ops->device_control(
258 			SST_SND_STREAM_INIT, &stream->stream_info);
259 	if (ret_val)
260 		pr_err("control_set ret error %d\n", ret_val);
261 	return ret_val;
262 
263 }
264 /* end -- helper functions */
265 
sst_platform_open(struct snd_pcm_substream * substream)266 static int sst_platform_open(struct snd_pcm_substream *substream)
267 {
268 	struct snd_pcm_runtime *runtime = substream->runtime;
269 	struct sst_runtime_stream *stream;
270 	int ret_val;
271 
272 	pr_debug("sst_platform_open called\n");
273 
274 	snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw);
275 	ret_val = snd_pcm_hw_constraint_integer(runtime,
276 						SNDRV_PCM_HW_PARAM_PERIODS);
277 	if (ret_val < 0)
278 		return ret_val;
279 
280 	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
281 	if (!stream)
282 		return -ENOMEM;
283 	spin_lock_init(&stream->status_lock);
284 
285 	/* get the sst ops */
286 	mutex_lock(&sst_lock);
287 	if (!sst) {
288 		pr_err("no device available to run\n");
289 		mutex_unlock(&sst_lock);
290 		kfree(stream);
291 		return -ENODEV;
292 	}
293 	if (!try_module_get(sst->dev->driver->owner)) {
294 		mutex_unlock(&sst_lock);
295 		kfree(stream);
296 		return -ENODEV;
297 	}
298 	stream->ops = sst->ops;
299 	mutex_unlock(&sst_lock);
300 
301 	stream->stream_info.str_id = 0;
302 	sst_set_stream_status(stream, SST_PLATFORM_INIT);
303 	stream->stream_info.mad_substream = substream;
304 	/* allocate memory for SST API set */
305 	runtime->private_data = stream;
306 
307 	return 0;
308 }
309 
sst_platform_close(struct snd_pcm_substream * substream)310 static int sst_platform_close(struct snd_pcm_substream *substream)
311 {
312 	struct sst_runtime_stream *stream;
313 	int ret_val = 0, str_id;
314 
315 	pr_debug("sst_platform_close called\n");
316 	stream = substream->runtime->private_data;
317 	str_id = stream->stream_info.str_id;
318 	if (str_id)
319 		ret_val = stream->ops->close(str_id);
320 	module_put(sst->dev->driver->owner);
321 	kfree(stream);
322 	return ret_val;
323 }
324 
sst_platform_pcm_prepare(struct snd_pcm_substream * substream)325 static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
326 {
327 	struct sst_runtime_stream *stream;
328 	int ret_val = 0, str_id;
329 
330 	pr_debug("sst_platform_pcm_prepare called\n");
331 	stream = substream->runtime->private_data;
332 	str_id = stream->stream_info.str_id;
333 	if (stream->stream_info.str_id) {
334 		ret_val = stream->ops->device_control(
335 				SST_SND_DROP, &str_id);
336 		return ret_val;
337 	}
338 
339 	ret_val = sst_platform_alloc_stream(substream);
340 	if (ret_val < 0)
341 		return ret_val;
342 	snprintf(substream->pcm->id, sizeof(substream->pcm->id),
343 			"%d", stream->stream_info.str_id);
344 
345 	ret_val = sst_platform_init_stream(substream);
346 	if (ret_val)
347 		return ret_val;
348 	substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
349 	return ret_val;
350 }
351 
sst_platform_pcm_trigger(struct snd_pcm_substream * substream,int cmd)352 static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
353 					int cmd)
354 {
355 	int ret_val = 0, str_id;
356 	struct sst_runtime_stream *stream;
357 	int str_cmd, status;
358 
359 	pr_debug("sst_platform_pcm_trigger called\n");
360 	stream = substream->runtime->private_data;
361 	str_id = stream->stream_info.str_id;
362 	switch (cmd) {
363 	case SNDRV_PCM_TRIGGER_START:
364 		pr_debug("sst: Trigger Start\n");
365 		str_cmd = SST_SND_START;
366 		status = SST_PLATFORM_RUNNING;
367 		stream->stream_info.mad_substream = substream;
368 		break;
369 	case SNDRV_PCM_TRIGGER_STOP:
370 		pr_debug("sst: in stop\n");
371 		str_cmd = SST_SND_DROP;
372 		status = SST_PLATFORM_DROPPED;
373 		break;
374 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
375 		pr_debug("sst: in pause\n");
376 		str_cmd = SST_SND_PAUSE;
377 		status = SST_PLATFORM_PAUSED;
378 		break;
379 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
380 		pr_debug("sst: in pause release\n");
381 		str_cmd = SST_SND_RESUME;
382 		status = SST_PLATFORM_RUNNING;
383 		break;
384 	default:
385 		return -EINVAL;
386 	}
387 	ret_val = stream->ops->device_control(str_cmd, &str_id);
388 	if (!ret_val)
389 		sst_set_stream_status(stream, status);
390 
391 	return ret_val;
392 }
393 
394 
sst_platform_pcm_pointer(struct snd_pcm_substream * substream)395 static snd_pcm_uframes_t sst_platform_pcm_pointer
396 			(struct snd_pcm_substream *substream)
397 {
398 	struct sst_runtime_stream *stream;
399 	int ret_val, status;
400 	struct pcm_stream_info *str_info;
401 
402 	stream = substream->runtime->private_data;
403 	status = sst_get_stream_status(stream);
404 	if (status == SST_PLATFORM_INIT)
405 		return 0;
406 	str_info = &stream->stream_info;
407 	ret_val = stream->ops->device_control(
408 				SST_SND_BUFFER_POINTER, str_info);
409 	if (ret_val) {
410 		pr_err("sst: error code = %d\n", ret_val);
411 		return ret_val;
412 	}
413 	return stream->stream_info.buffer_ptr;
414 }
415 
sst_platform_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)416 static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
417 		struct snd_pcm_hw_params *params)
418 {
419 	snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
420 	memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
421 
422 	return 0;
423 }
424 
sst_platform_pcm_hw_free(struct snd_pcm_substream * substream)425 static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
426 {
427 	return snd_pcm_lib_free_pages(substream);
428 }
429 
430 static struct snd_pcm_ops sst_platform_ops = {
431 	.open = sst_platform_open,
432 	.close = sst_platform_close,
433 	.ioctl = snd_pcm_lib_ioctl,
434 	.prepare = sst_platform_pcm_prepare,
435 	.trigger = sst_platform_pcm_trigger,
436 	.pointer = sst_platform_pcm_pointer,
437 	.hw_params = sst_platform_pcm_hw_params,
438 	.hw_free = sst_platform_pcm_hw_free,
439 };
440 
sst_pcm_free(struct snd_pcm * pcm)441 static void sst_pcm_free(struct snd_pcm *pcm)
442 {
443 	pr_debug("sst_pcm_free called\n");
444 	snd_pcm_lib_preallocate_free_for_all(pcm);
445 }
446 
sst_pcm_new(struct snd_soc_pcm_runtime * rtd)447 static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
448 {
449 	struct snd_pcm *pcm = rtd->pcm;
450 	int retval = 0;
451 
452 	pr_debug("sst_pcm_new called\n");
453 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
454 			pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
455 		retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
456 			SNDRV_DMA_TYPE_CONTINUOUS,
457 			snd_dma_continuous_data(GFP_KERNEL),
458 			SST_MIN_BUFFER, SST_MAX_BUFFER);
459 		if (retval) {
460 			pr_err("dma buffer allocationf fail\n");
461 			return retval;
462 		}
463 	}
464 	return retval;
465 }
466 static struct snd_soc_platform_driver sst_soc_platform_drv = {
467 	.ops		= &sst_platform_ops,
468 	.pcm_new	= sst_pcm_new,
469 	.pcm_free	= sst_pcm_free,
470 };
471 
sst_platform_probe(struct platform_device * pdev)472 static int sst_platform_probe(struct platform_device *pdev)
473 {
474 	int ret;
475 
476 	pr_debug("sst_platform_probe called\n");
477 	sst = NULL;
478 	ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
479 	if (ret) {
480 		pr_err("registering soc platform failed\n");
481 		return ret;
482 	}
483 
484 	ret = snd_soc_register_dais(&pdev->dev,
485 				sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
486 	if (ret) {
487 		pr_err("registering cpu dais failed\n");
488 		snd_soc_unregister_platform(&pdev->dev);
489 	}
490 	return ret;
491 }
492 
sst_platform_remove(struct platform_device * pdev)493 static int sst_platform_remove(struct platform_device *pdev)
494 {
495 
496 	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
497 	snd_soc_unregister_platform(&pdev->dev);
498 	pr_debug("sst_platform_remove success\n");
499 	return 0;
500 }
501 
502 static struct platform_driver sst_platform_driver = {
503 	.driver		= {
504 		.name		= "sst-platform",
505 		.owner		= THIS_MODULE,
506 	},
507 	.probe		= sst_platform_probe,
508 	.remove		= sst_platform_remove,
509 };
510 
511 module_platform_driver(sst_platform_driver);
512 
513 MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
514 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
515 MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
516 MODULE_LICENSE("GPL v2");
517 MODULE_ALIAS("platform:sst-platform");
518