blob: 28b5e11068554e1cd3c526419d5fd4b2e34db634 [file] [log] [blame]
John Stultza4749bb2015-05-08 12:57:36 -07001#include <linux/kernel.h>
2#include <linux/device.h>
3#include <linux/interrupt.h>
4#include <linux/module.h>
5#include <linux/platform_device.h>
6#include <linux/workqueue.h>
7#include <linux/i2c.h>
8#include <sound/core.h>
9#include <sound/pcm.h>
10#include <sound/pcm_params.h>
11#include <sound/soc.h>
12#include <sound/dmaengine_pcm.h>
13#include <sound/simple_card.h>
14#include "greybus.h"
15#include "gpbridge.h"
16#include "audio.h"
17
18/*
19 * timer/workqueue logic for pushing pcm data.
20 *
21 * Since when we are playing audio, we don't get any
22 * status or feedback from the codec, we have to use a
23 * hrtimer to trigger sending data to the remote codec.
24 * However since the hrtimer runs in irq context, so we
25 * have to schedule a workqueue to actually send the
26 * greybus data.
27 */
28
29static void gb_pcm_work(struct work_struct *work)
30{
31 struct gb_snd *snd_dev = container_of(work, struct gb_snd, work);
32 struct snd_pcm_substream *substream = snd_dev->substream;
33 struct snd_pcm_runtime *runtime = substream->runtime;
34 unsigned int stride, frames, oldptr;
35 int period_elapsed;
36 char *address;
37 long len;
38
39 if (!snd_dev)
40 return;
41
42 if (!atomic_read(&snd_dev->running))
43 return;
44
45 address = runtime->dma_area + snd_dev->hwptr_done;
46
47 len = frames_to_bytes(runtime,
48 runtime->buffer_size) - snd_dev->hwptr_done;
49 len = min(len, MAX_SEND_DATA_LEN);
50 gb_i2s_send_data(snd_dev->i2s_tx_connection, snd_dev->send_data_req_buf,
51 address, len, snd_dev->send_data_sample_count);
52
53 snd_dev->send_data_sample_count += CONFIG_SAMPLES_PER_MSG;
54
55 stride = runtime->frame_bits >> 3;
56 frames = len/stride;
57
58 snd_pcm_stream_lock(substream);
59 oldptr = snd_dev->hwptr_done;
60 snd_dev->hwptr_done += len;
61 if (snd_dev->hwptr_done >= runtime->buffer_size * stride)
62 snd_dev->hwptr_done -= runtime->buffer_size * stride;
63
64 frames = (len + (oldptr % stride)) / stride;
65
66 snd_dev->transfer_done += frames;
67 if (snd_dev->transfer_done >= runtime->period_size) {
68 snd_dev->transfer_done -= runtime->period_size;
69 period_elapsed = 1;
70 }
71
72 snd_pcm_stream_unlock(substream);
73 if (period_elapsed)
74 snd_pcm_period_elapsed(snd_dev->substream);
75}
76
77static enum hrtimer_restart gb_pcm_timer_function(struct hrtimer *hrtimer)
78{
79 struct gb_snd *snd_dev = container_of(hrtimer, struct gb_snd, timer);
80
81 if (!atomic_read(&snd_dev->running))
82 return HRTIMER_NORESTART;
83 queue_work(snd_dev->workqueue, &snd_dev->work);
84 hrtimer_forward_now(hrtimer, ns_to_ktime(CONFIG_PERIOD_NS));
85 return HRTIMER_RESTART;
86}
87
88void gb_pcm_hrtimer_start(struct gb_snd *snd_dev)
89{
90 atomic_set(&snd_dev->running, 1);
91 hrtimer_start(&snd_dev->timer, ns_to_ktime(CONFIG_PERIOD_NS),
92 HRTIMER_MODE_REL);
93}
94
95void gb_pcm_hrtimer_stop(struct gb_snd *snd_dev)
96{
97 atomic_set(&snd_dev->running, 0);
98 hrtimer_cancel(&snd_dev->timer);
99}
100
101static int gb_pcm_hrtimer_init(struct gb_snd *snd_dev)
102{
103 hrtimer_init(&snd_dev->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
104 snd_dev->timer.function = gb_pcm_timer_function;
105 atomic_set(&snd_dev->running, 0);
106 snd_dev->workqueue = alloc_workqueue("gb-audio", WQ_HIGHPRI, 0);
107 if (!snd_dev->workqueue)
108 return -ENOMEM;
109 INIT_WORK(&snd_dev->work, gb_pcm_work);
110 return 0;
111}
112
113
114/*
115 * Core gb pcm structure
116 */
117static struct snd_pcm_hardware gb_plat_pcm_hardware = {
118 .info = SNDRV_PCM_INFO_INTERLEAVED |
119 SNDRV_PCM_INFO_MMAP |
120 SNDRV_PCM_INFO_MMAP_VALID,
121 .formats = GB_FMTS,
122 .rates = GB_RATES,
123 .rate_min = 8000,
124 .rate_max = GB_SAMPLE_RATE,
125 .channels_min = 1,
126 .channels_max = 2,
127 /* XXX - All the values below are junk */
128 .buffer_bytes_max = 64 * 1024,
129 .period_bytes_min = 32,
130 .period_bytes_max = 8192,
131 .periods_min = 2,
132 .periods_max = 32,
133};
134
135static snd_pcm_uframes_t gb_pcm_pointer(struct snd_pcm_substream *substream)
136{
137 struct snd_soc_pcm_runtime *rtd = substream->private_data;
138 struct gb_snd *snd_dev;
139
140 snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
141
142 return snd_dev->hwptr_done / (substream->runtime->frame_bits >> 3);
143}
144
145static int gb_pcm_prepare(struct snd_pcm_substream *substream)
146{
147 struct snd_soc_pcm_runtime *rtd = substream->private_data;
148 struct gb_snd *snd_dev;
149
150 snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
151 snd_dev->hwptr_done = 0;
152 snd_dev->transfer_done = 0;
153 return 0;
154}
155
156static unsigned int rates[] = {GB_SAMPLE_RATE};
157static struct snd_pcm_hw_constraint_list constraints_rates = {
158 .count = ARRAY_SIZE(rates),
159 .list = rates,
160 .mask = 0,
161};
162
163static int gb_pcm_open(struct snd_pcm_substream *substream)
164{
165 struct snd_pcm_runtime *runtime = substream->runtime;
166 struct snd_soc_pcm_runtime *rtd = substream->private_data;
167 struct gb_snd *snd_dev;
168 unsigned long flags;
169 int ret;
170
171 snd_dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
172
173 spin_lock_irqsave(&snd_dev->lock, flags);
174 runtime->private_data = snd_dev;
175 snd_dev->substream = substream;
176 ret = gb_pcm_hrtimer_init(snd_dev);
177 spin_unlock_irqrestore(&snd_dev->lock, flags);
178
179 if (ret)
180 return ret;
181
182 snd_soc_set_runtime_hwparams(substream, &gb_plat_pcm_hardware);
183
184 ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
185 SNDRV_PCM_HW_PARAM_RATE,
186 &constraints_rates);
187 if (ret < 0)
188 return ret;
189
190 return snd_pcm_hw_constraint_integer(runtime,
191 SNDRV_PCM_HW_PARAM_PERIODS);
192}
193
194static int gb_pcm_close(struct snd_pcm_substream *substream)
195{
196 substream->runtime->private_data = NULL;
197 return 0;
198}
199
200static int gb_pcm_hw_params(struct snd_pcm_substream *substream,
201 struct snd_pcm_hw_params *hw_params)
202{
203 return snd_pcm_lib_malloc_pages(substream,
204 params_buffer_bytes(hw_params));
205}
206
207static int gb_pcm_hw_free(struct snd_pcm_substream *substream)
208{
209 return snd_pcm_lib_free_pages(substream);
210}
211
212static struct snd_pcm_ops gb_pcm_ops = {
213 .open = gb_pcm_open,
214 .close = gb_pcm_close,
215 .ioctl = snd_pcm_lib_ioctl,
216 .hw_params = gb_pcm_hw_params,
217 .hw_free = gb_pcm_hw_free,
218 .prepare = gb_pcm_prepare,
219 .pointer = gb_pcm_pointer,
220};
221
222static void gb_pcm_free(struct snd_pcm *pcm)
223{
224 snd_pcm_lib_preallocate_free_for_all(pcm);
225}
226
227static int gb_pcm_new(struct snd_soc_pcm_runtime *rtd)
228{
229 struct snd_pcm *pcm = rtd->pcm;
230
231 return snd_pcm_lib_preallocate_pages_for_all(
232 pcm,
233 SNDRV_DMA_TYPE_CONTINUOUS,
234 snd_dma_continuous_data(GFP_KERNEL),
235 PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
236}
237
238struct snd_soc_platform_driver gb_soc_platform = {
239 .ops = &gb_pcm_ops,
240 .pcm_new = gb_pcm_new,
241 .pcm_free = gb_pcm_free,
242};
243
244static int gb_soc_platform_probe(struct platform_device *pdev)
245{
246 return snd_soc_register_platform(&pdev->dev, &gb_soc_platform);
247}
248
249static int gb_soc_platform_remove(struct platform_device *pdev)
250{
251 snd_soc_unregister_platform(&pdev->dev);
252 return 0;
253}
254
255struct platform_driver gb_audio_pcm_driver = {
256 .driver = {
257 .name = "gb-pcm-audio",
258 .owner = THIS_MODULE,
259 },
260 .probe = gb_soc_platform_probe,
261 .remove = gb_soc_platform_remove,
262};