Commit | Line | Data |
---|---|---|
01a0c113 OL |
1 | /* |
2 | * Copyright (C) ST-Ericsson SA 2012 | |
3 | * | |
4 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, | |
5 | * Roger Nilsson <roger.xr.nilsson@stericsson.com> | |
6 | * for ST-Ericsson. | |
7 | * | |
8 | * License terms: | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as published | |
12 | * by the Free Software Foundation. | |
13 | */ | |
14 | ||
15 | #include <asm/page.h> | |
16 | ||
17 | #include <linux/module.h> | |
18 | #include <linux/dma-mapping.h> | |
19 | #include <linux/dmaengine.h> | |
20 | #include <linux/slab.h> | |
865fab60 | 21 | #include <linux/platform_data/dma-ste-dma40.h> |
01a0c113 OL |
22 | |
23 | #include <sound/pcm.h> | |
24 | #include <sound/pcm_params.h> | |
25 | #include <sound/soc.h> | |
26 | #include <sound/dmaengine_pcm.h> | |
27 | ||
28 | #include "ux500_msp_i2s.h" | |
29 | #include "ux500_pcm.h" | |
30 | ||
69b6f196 LPC |
31 | #define UX500_PLATFORM_MIN_RATE 8000 |
32 | #define UX500_PLATFORM_MAX_RATE 48000 | |
33 | ||
34 | #define UX500_PLATFORM_MIN_CHANNELS 1 | |
35 | #define UX500_PLATFORM_MAX_CHANNELS 8 | |
36 | ||
37 | #define UX500_PLATFORM_PERIODS_BYTES_MIN 128 | |
38 | #define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) | |
39 | #define UX500_PLATFORM_PERIODS_MIN 2 | |
40 | #define UX500_PLATFORM_PERIODS_MAX 48 | |
41 | #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) | |
01a0c113 | 42 | |
22f38f79 | 43 | static const struct snd_pcm_hardware ux500_pcm_hw = { |
01a0c113 OL |
44 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
45 | SNDRV_PCM_INFO_MMAP | | |
46 | SNDRV_PCM_INFO_RESUME | | |
47 | SNDRV_PCM_INFO_PAUSE, | |
48 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | |
49 | SNDRV_PCM_FMTBIT_U16_LE | | |
50 | SNDRV_PCM_FMTBIT_S16_BE | | |
51 | SNDRV_PCM_FMTBIT_U16_BE, | |
52 | .rates = SNDRV_PCM_RATE_KNOT, | |
69b6f196 LPC |
53 | .rate_min = UX500_PLATFORM_MIN_RATE, |
54 | .rate_max = UX500_PLATFORM_MAX_RATE, | |
01a0c113 OL |
55 | .channels_min = UX500_PLATFORM_MIN_CHANNELS, |
56 | .channels_max = UX500_PLATFORM_MAX_CHANNELS, | |
57 | .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, | |
58 | .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, | |
59 | .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, | |
60 | .periods_min = UX500_PLATFORM_PERIODS_MIN, | |
61 | .periods_max = UX500_PLATFORM_PERIODS_MAX, | |
62 | }; | |
63 | ||
22f38f79 LPC |
64 | static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, |
65 | struct snd_pcm_substream *substream) | |
01a0c113 | 66 | { |
01a0c113 OL |
67 | struct snd_soc_dai *dai = rtd->cpu_dai; |
68 | struct device *dev = dai->dev; | |
01a0c113 OL |
69 | u16 per_data_width, mem_data_width; |
70 | struct stedma40_chan_cfg *dma_cfg; | |
22f38f79 | 71 | struct ux500_msp_dma_params *dma_params; |
01a0c113 OL |
72 | |
73 | dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, | |
74 | snd_pcm_stream_str(substream)); | |
75 | ||
22f38f79 LPC |
76 | dma_params = snd_soc_dai_get_dma_data(dai, substream); |
77 | dma_cfg = dma_params->dma_cfg; | |
01a0c113 OL |
78 | |
79 | mem_data_width = STEDMA40_HALFWORD_WIDTH; | |
80 | ||
01a0c113 OL |
81 | switch (dma_params->data_size) { |
82 | case 32: | |
83 | per_data_width = STEDMA40_WORD_WIDTH; | |
84 | break; | |
85 | case 16: | |
86 | per_data_width = STEDMA40_HALFWORD_WIDTH; | |
87 | break; | |
88 | case 8: | |
89 | per_data_width = STEDMA40_BYTE_WIDTH; | |
90 | break; | |
91 | default: | |
92 | per_data_width = STEDMA40_WORD_WIDTH; | |
01a0c113 OL |
93 | } |
94 | ||
01a0c113 OL |
95 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
96 | dma_cfg->src_info.data_width = mem_data_width; | |
97 | dma_cfg->dst_info.data_width = per_data_width; | |
98 | } else { | |
99 | dma_cfg->src_info.data_width = per_data_width; | |
100 | dma_cfg->dst_info.data_width = mem_data_width; | |
101 | } | |
102 | ||
22f38f79 | 103 | return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg); |
01a0c113 OL |
104 | } |
105 | ||
22f38f79 LPC |
106 | static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = { |
107 | .pcm_hardware = &ux500_pcm_hw, | |
108 | .compat_request_channel = ux500_pcm_request_chan, | |
109 | .prealloc_buffer_size = 128 * 1024, | |
01a0c113 OL |
110 | }; |
111 | ||
da794876 | 112 | int ux500_pcm_register_platform(struct platform_device *pdev) |
01a0c113 OL |
113 | { |
114 | int ret; | |
115 | ||
22f38f79 LPC |
116 | ret = snd_dmaengine_pcm_register(&pdev->dev, |
117 | &ux500_dmaengine_pcm_config, | |
118 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | | |
119 | SND_DMAENGINE_PCM_FLAG_COMPAT | | |
120 | SND_DMAENGINE_PCM_FLAG_NO_DT); | |
01a0c113 OL |
121 | if (ret < 0) { |
122 | dev_err(&pdev->dev, | |
123 | "%s: ERROR: Failed to register platform '%s' (%d)!\n", | |
124 | __func__, pdev->name, ret); | |
125 | return ret; | |
126 | } | |
127 | ||
128 | return 0; | |
129 | } | |
1428c20f | 130 | EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); |
01a0c113 | 131 | |
da794876 | 132 | int ux500_pcm_unregister_platform(struct platform_device *pdev) |
01a0c113 | 133 | { |
22f38f79 | 134 | snd_dmaengine_pcm_unregister(&pdev->dev); |
01a0c113 OL |
135 | return 0; |
136 | } | |
1428c20f | 137 | EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); |