diff options
Diffstat (limited to 'sound/soc/imx')
-rw-r--r-- | sound/soc/imx/Kconfig | 2 | ||||
-rw-r--r-- | sound/soc/imx/imx-pcm-dma-mx2.c | 24 | ||||
-rw-r--r-- | sound/soc/imx/imx-pcm-fiq.c | 56 | ||||
-rw-r--r-- | sound/soc/imx/imx-ssi.c | 11 |
4 files changed, 60 insertions, 33 deletions
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index c7d0fd9b7de8..7174b4c710de 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_IMX_SOC | 1 | config SND_IMX_SOC |
2 | tristate "SoC Audio for Freescale i.MX CPUs" | 2 | tristate "SoC Audio for Freescale i.MX CPUs" |
3 | depends on ARCH_MXC && BROKEN | 3 | depends on ARCH_MXC |
4 | select SND_PCM | 4 | select SND_PCM |
5 | select FIQ | 5 | select FIQ |
6 | select SND_SOC_AC97_BUS | 6 | select SND_SOC_AC97_BUS |
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c index 19452e44afdc..2b31ac673ea4 100644 --- a/sound/soc/imx/imx-pcm-dma-mx2.c +++ b/sound/soc/imx/imx-pcm-dma-mx2.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> | ||
22 | 23 | ||
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
24 | #include <sound/initval.h> | 25 | #include <sound/initval.h> |
@@ -70,7 +71,12 @@ static void imx_ssi_dma_callback(int channel, void *data) | |||
70 | 71 | ||
71 | static void snd_imx_dma_err_callback(int channel, void *data, int err) | 72 | static void snd_imx_dma_err_callback(int channel, void *data, int err) |
72 | { | 73 | { |
73 | pr_err("DMA error callback called\n"); | 74 | struct snd_pcm_substream *substream = data; |
75 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
76 | struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; | ||
77 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
78 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
79 | int ret; | ||
74 | 80 | ||
75 | pr_err("DMA timeout on channel %d -%s%s%s%s\n", | 81 | pr_err("DMA timeout on channel %d -%s%s%s%s\n", |
76 | channel, | 82 | channel, |
@@ -78,16 +84,26 @@ static void snd_imx_dma_err_callback(int channel, void *data, int err) | |||
78 | err & IMX_DMA_ERR_REQUEST ? " request" : "", | 84 | err & IMX_DMA_ERR_REQUEST ? " request" : "", |
79 | err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", | 85 | err & IMX_DMA_ERR_TRANSFER ? " transfer" : "", |
80 | err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); | 86 | err & IMX_DMA_ERR_BUFFER ? " buffer" : ""); |
87 | |||
88 | imx_dma_disable(iprtd->dma); | ||
89 | ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count, | ||
90 | IMX_DMA_LENGTH_LOOP, dma_params->dma_addr, | ||
91 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
92 | DMA_MODE_WRITE : DMA_MODE_READ); | ||
93 | if (!ret) | ||
94 | imx_dma_enable(iprtd->dma); | ||
81 | } | 95 | } |
82 | 96 | ||
83 | static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) | 97 | static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream) |
84 | { | 98 | { |
85 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 99 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
86 | struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; | 100 | struct imx_pcm_dma_params *dma_params; |
87 | struct snd_pcm_runtime *runtime = substream->runtime; | 101 | struct snd_pcm_runtime *runtime = substream->runtime; |
88 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | 102 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; |
89 | int ret; | 103 | int ret; |
90 | 104 | ||
105 | dma_params = snd_soc_get_dma_data(rtd->dai->cpu_dai, substream); | ||
106 | |||
91 | iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); | 107 | iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH); |
92 | if (iprtd->dma < 0) { | 108 | if (iprtd->dma < 0) { |
93 | pr_err("Failed to claim the audio DMA\n"); | 109 | pr_err("Failed to claim the audio DMA\n"); |
@@ -192,10 +208,12 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream) | |||
192 | { | 208 | { |
193 | struct snd_pcm_runtime *runtime = substream->runtime; | 209 | struct snd_pcm_runtime *runtime = substream->runtime; |
194 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 210 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
195 | struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; | 211 | struct imx_pcm_dma_params *dma_params; |
196 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | 212 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; |
197 | int err; | 213 | int err; |
198 | 214 | ||
215 | dma_params = snd_soc_get_dma_data(rtd->dai->cpu_dai, substream); | ||
216 | |||
199 | iprtd->substream = substream; | 217 | iprtd->substream = substream; |
200 | iprtd->buf = (unsigned int *)substream->dma_buffer.area; | 218 | iprtd->buf = (unsigned int *)substream->dma_buffer.area; |
201 | iprtd->period_cnt = 0; | 219 | iprtd->period_cnt = 0; |
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c index d9cb9849b033..6b518e07eea9 100644 --- a/sound/soc/imx/imx-pcm-fiq.c +++ b/sound/soc/imx/imx-pcm-fiq.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> | ||
22 | 23 | ||
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
24 | #include <sound/initval.h> | 25 | #include <sound/initval.h> |
@@ -38,23 +39,24 @@ struct imx_pcm_runtime_data { | |||
38 | unsigned long offset; | 39 | unsigned long offset; |
39 | unsigned long last_offset; | 40 | unsigned long last_offset; |
40 | unsigned long size; | 41 | unsigned long size; |
41 | struct timer_list timer; | 42 | struct hrtimer hrt; |
42 | int poll_time; | 43 | int poll_time_ns; |
44 | struct snd_pcm_substream *substream; | ||
45 | atomic_t running; | ||
43 | }; | 46 | }; |
44 | 47 | ||
45 | static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd) | 48 | static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) |
46 | { | 49 | { |
47 | iprtd->timer.expires = jiffies + iprtd->poll_time; | 50 | struct imx_pcm_runtime_data *iprtd = |
48 | } | 51 | container_of(hrt, struct imx_pcm_runtime_data, hrt); |
49 | 52 | struct snd_pcm_substream *substream = iprtd->substream; | |
50 | static void imx_ssi_timer_callback(unsigned long data) | ||
51 | { | ||
52 | struct snd_pcm_substream *substream = (void *)data; | ||
53 | struct snd_pcm_runtime *runtime = substream->runtime; | 53 | struct snd_pcm_runtime *runtime = substream->runtime; |
54 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
55 | struct pt_regs regs; | 54 | struct pt_regs regs; |
56 | unsigned long delta; | 55 | unsigned long delta; |
57 | 56 | ||
57 | if (!atomic_read(&iprtd->running)) | ||
58 | return HRTIMER_NORESTART; | ||
59 | |||
58 | get_fiq_regs(®s); | 60 | get_fiq_regs(®s); |
59 | 61 | ||
60 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 62 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
@@ -71,16 +73,14 @@ static void imx_ssi_timer_callback(unsigned long data) | |||
71 | 73 | ||
72 | /* If we've transferred at least a period then report it and | 74 | /* If we've transferred at least a period then report it and |
73 | * reset our poll time */ | 75 | * reset our poll time */ |
74 | if (delta >= runtime->period_size) { | 76 | if (delta >= iprtd->period) { |
75 | snd_pcm_period_elapsed(substream); | 77 | snd_pcm_period_elapsed(substream); |
76 | iprtd->last_offset = iprtd->offset; | 78 | iprtd->last_offset = iprtd->offset; |
77 | |||
78 | imx_ssi_set_next_poll(iprtd); | ||
79 | } | 79 | } |
80 | 80 | ||
81 | /* Restart the timer; if we didn't report we'll run on the next tick */ | 81 | hrtimer_forward_now(hrt, ns_to_ktime(iprtd->poll_time_ns)); |
82 | add_timer(&iprtd->timer); | ||
83 | 82 | ||
83 | return HRTIMER_RESTART; | ||
84 | } | 84 | } |
85 | 85 | ||
86 | static struct fiq_handler fh = { | 86 | static struct fiq_handler fh = { |
@@ -98,8 +98,8 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
98 | iprtd->period = params_period_bytes(params) ; | 98 | iprtd->period = params_period_bytes(params) ; |
99 | iprtd->offset = 0; | 99 | iprtd->offset = 0; |
100 | iprtd->last_offset = 0; | 100 | iprtd->last_offset = 0; |
101 | iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params)); | 101 | iprtd->poll_time_ns = 1000000000 / params_rate(params) * |
102 | 102 | params_period_size(params); | |
103 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 103 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); |
104 | 104 | ||
105 | return 0; | 105 | return 0; |
@@ -134,8 +134,9 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
134 | case SNDRV_PCM_TRIGGER_START: | 134 | case SNDRV_PCM_TRIGGER_START: |
135 | case SNDRV_PCM_TRIGGER_RESUME: | 135 | case SNDRV_PCM_TRIGGER_RESUME: |
136 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 136 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
137 | imx_ssi_set_next_poll(iprtd); | 137 | atomic_set(&iprtd->running, 1); |
138 | add_timer(&iprtd->timer); | 138 | hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns), |
139 | HRTIMER_MODE_REL); | ||
139 | if (++fiq_enable == 1) | 140 | if (++fiq_enable == 1) |
140 | enable_fiq(imx_pcm_fiq); | 141 | enable_fiq(imx_pcm_fiq); |
141 | 142 | ||
@@ -144,11 +145,11 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
144 | case SNDRV_PCM_TRIGGER_STOP: | 145 | case SNDRV_PCM_TRIGGER_STOP: |
145 | case SNDRV_PCM_TRIGGER_SUSPEND: | 146 | case SNDRV_PCM_TRIGGER_SUSPEND: |
146 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 147 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
147 | del_timer(&iprtd->timer); | 148 | atomic_set(&iprtd->running, 0); |
149 | |||
148 | if (--fiq_enable == 0) | 150 | if (--fiq_enable == 0) |
149 | disable_fiq(imx_pcm_fiq); | 151 | disable_fiq(imx_pcm_fiq); |
150 | 152 | ||
151 | |||
152 | break; | 153 | break; |
153 | default: | 154 | default: |
154 | return -EINVAL; | 155 | return -EINVAL; |
@@ -179,7 +180,7 @@ static struct snd_pcm_hardware snd_imx_hardware = { | |||
179 | .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, | 180 | .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, |
180 | .period_bytes_min = 128, | 181 | .period_bytes_min = 128, |
181 | .period_bytes_max = 16 * 1024, | 182 | .period_bytes_max = 16 * 1024, |
182 | .periods_min = 2, | 183 | .periods_min = 4, |
183 | .periods_max = 255, | 184 | .periods_max = 255, |
184 | .fifo_size = 0, | 185 | .fifo_size = 0, |
185 | }; | 186 | }; |
@@ -193,9 +194,11 @@ static int snd_imx_open(struct snd_pcm_substream *substream) | |||
193 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); | 194 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); |
194 | runtime->private_data = iprtd; | 195 | runtime->private_data = iprtd; |
195 | 196 | ||
196 | init_timer(&iprtd->timer); | 197 | iprtd->substream = substream; |
197 | iprtd->timer.data = (unsigned long)substream; | 198 | |
198 | iprtd->timer.function = imx_ssi_timer_callback; | 199 | atomic_set(&iprtd->running, 0); |
200 | hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
201 | iprtd->hrt.function = snd_hrtimer_callback; | ||
199 | 202 | ||
200 | ret = snd_pcm_hw_constraint_integer(substream->runtime, | 203 | ret = snd_pcm_hw_constraint_integer(substream->runtime, |
201 | SNDRV_PCM_HW_PARAM_PERIODS); | 204 | SNDRV_PCM_HW_PARAM_PERIODS); |
@@ -211,7 +214,8 @@ static int snd_imx_close(struct snd_pcm_substream *substream) | |||
211 | struct snd_pcm_runtime *runtime = substream->runtime; | 214 | struct snd_pcm_runtime *runtime = substream->runtime; |
212 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | 215 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; |
213 | 216 | ||
214 | del_timer_sync(&iprtd->timer); | 217 | hrtimer_cancel(&iprtd->hrt); |
218 | |||
215 | kfree(iprtd); | 219 | kfree(iprtd); |
216 | 220 | ||
217 | return 0; | 221 | return 0; |
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index 56f46a75d297..80b4fee2442b 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
40 | #include <linux/module.h> | 40 | #include <linux/module.h> |
41 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <linux/slab.h> | ||
42 | 43 | ||
43 | #include <sound/core.h> | 44 | #include <sound/core.h> |
44 | #include <sound/initval.h> | 45 | #include <sound/initval.h> |
@@ -234,17 +235,20 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream, | |||
234 | struct snd_soc_dai *cpu_dai) | 235 | struct snd_soc_dai *cpu_dai) |
235 | { | 236 | { |
236 | struct imx_ssi *ssi = cpu_dai->private_data; | 237 | struct imx_ssi *ssi = cpu_dai->private_data; |
238 | struct imx_pcm_dma_params *dma_data; | ||
237 | u32 reg, sccr; | 239 | u32 reg, sccr; |
238 | 240 | ||
239 | /* Tx/Rx config */ | 241 | /* Tx/Rx config */ |
240 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 242 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
241 | reg = SSI_STCCR; | 243 | reg = SSI_STCCR; |
242 | cpu_dai->dma_data = &ssi->dma_params_tx; | 244 | dma_data = &ssi->dma_params_tx; |
243 | } else { | 245 | } else { |
244 | reg = SSI_SRCCR; | 246 | reg = SSI_SRCCR; |
245 | cpu_dai->dma_data = &ssi->dma_params_rx; | 247 | dma_data = &ssi->dma_params_rx; |
246 | } | 248 | } |
247 | 249 | ||
250 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); | ||
251 | |||
248 | sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; | 252 | sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK; |
249 | 253 | ||
250 | /* DAI data (word) size */ | 254 | /* DAI data (word) size */ |
@@ -652,7 +656,8 @@ static int imx_ssi_probe(struct platform_device *pdev) | |||
652 | dai->private_data = ssi; | 656 | dai->private_data = ssi; |
653 | 657 | ||
654 | if ((cpu_is_mx27() || cpu_is_mx21()) && | 658 | if ((cpu_is_mx27() || cpu_is_mx21()) && |
655 | !(ssi->flags & IMX_SSI_USE_AC97)) { | 659 | !(ssi->flags & IMX_SSI_USE_AC97) && |
660 | (ssi->flags & IMX_SSI_DMA)) { | ||
656 | ssi->flags |= IMX_SSI_DMA; | 661 | ssi->flags |= IMX_SSI_DMA; |
657 | platform = imx_ssi_dma_mx2_init(pdev, ssi); | 662 | platform = imx_ssi_dma_mx2_init(pdev, ssi); |
658 | } else | 663 | } else |