greybus: gb-audio: Add integrated greybus audio driver
[cascardo/linux.git] / drivers / staging / greybus / audio-pcm.c
1 #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
29 static 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
77 static 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
88 void 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
95 void 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
101 static 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  */
117 static 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
135 static 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
145 static 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
156 static unsigned int rates[] = {GB_SAMPLE_RATE};
157 static struct snd_pcm_hw_constraint_list constraints_rates = {
158         .count = ARRAY_SIZE(rates),
159         .list = rates,
160         .mask = 0,
161 };
162
163 static 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
194 static int gb_pcm_close(struct snd_pcm_substream *substream)
195 {
196         substream->runtime->private_data = NULL;
197         return 0;
198 }
199
200 static 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
207 static int gb_pcm_hw_free(struct snd_pcm_substream *substream)
208 {
209         return snd_pcm_lib_free_pages(substream);
210 }
211
212 static 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
222 static void gb_pcm_free(struct snd_pcm *pcm)
223 {
224         snd_pcm_lib_preallocate_free_for_all(pcm);
225 }
226
227 static 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
238 struct 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
244 static int gb_soc_platform_probe(struct platform_device *pdev)
245 {
246         return snd_soc_register_platform(&pdev->dev, &gb_soc_platform);
247 }
248
249 static int gb_soc_platform_remove(struct platform_device *pdev)
250 {
251         snd_soc_unregister_platform(&pdev->dev);
252         return 0;
253 }
254
255 struct 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 };