Commit | Line | Data |
---|---|---|
dc641378 GL |
1 | /* |
2 | * Freescale MPC5200 PSC in I2S mode | |
3 | * ALSA SoC Digital Audio Interface (DAI) driver | |
4 | * | |
5 | * Copyright (C) 2008 Secret Lab Technologies Ltd. | |
6 | */ | |
7 | ||
8 | #include <linux/init.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/interrupt.h> | |
11 | #include <linux/device.h> | |
12 | #include <linux/delay.h> | |
13 | #include <linux/of_device.h> | |
14 | #include <linux/of_platform.h> | |
15 | #include <linux/dma-mapping.h> | |
16 | ||
17 | #include <sound/core.h> | |
18 | #include <sound/pcm.h> | |
19 | #include <sound/pcm_params.h> | |
20 | #include <sound/initval.h> | |
21 | #include <sound/soc.h> | |
22 | #include <sound/soc-of-simple.h> | |
23 | ||
24 | #include <sysdev/bestcomm/bestcomm.h> | |
25 | #include <sysdev/bestcomm/gen_bd.h> | |
26 | #include <asm/mpc52xx_psc.h> | |
27 | ||
28 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | |
29 | MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver"); | |
30 | MODULE_LICENSE("GPL"); | |
31 | ||
32 | /** | |
33 | * PSC_I2S_RATES: sample rates supported by the I2S | |
34 | * | |
35 | * This driver currently only supports the PSC running in I2S slave mode, | |
36 | * which means the codec determines the sample rate. Therefore, we tell | |
37 | * ALSA that we support all rates and let the codec driver decide what rates | |
38 | * are really supported. | |
39 | */ | |
40 | #define PSC_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \ | |
41 | SNDRV_PCM_RATE_CONTINUOUS) | |
42 | ||
43 | /** | |
44 | * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode | |
45 | */ | |
46 | #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ | |
47 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \ | |
48 | SNDRV_PCM_FMTBIT_S32_BE) | |
49 | ||
50 | /** | |
51 | * psc_i2s_stream - Data specific to a single stream (playback or capture) | |
52 | * @active: flag indicating if the stream is active | |
53 | * @psc_i2s: pointer back to parent psc_i2s data structure | |
54 | * @bcom_task: bestcomm task structure | |
55 | * @irq: irq number for bestcomm task | |
56 | * @period_start: physical address of start of DMA region | |
57 | * @period_end: physical address of end of DMA region | |
58 | * @period_next_pt: physical address of next DMA buffer to enqueue | |
59 | * @period_bytes: size of DMA period in bytes | |
60 | */ | |
61 | struct psc_i2s_stream { | |
62 | int active; | |
63 | struct psc_i2s *psc_i2s; | |
64 | struct bcom_task *bcom_task; | |
65 | int irq; | |
66 | struct snd_pcm_substream *stream; | |
67 | dma_addr_t period_start; | |
68 | dma_addr_t period_end; | |
69 | dma_addr_t period_next_pt; | |
70 | dma_addr_t period_current_pt; | |
71 | int period_bytes; | |
72 | }; | |
73 | ||
74 | /** | |
75 | * psc_i2s - Private driver data | |
76 | * @name: short name for this device ("PSC0", "PSC1", etc) | |
77 | * @psc_regs: pointer to the PSC's registers | |
78 | * @fifo_regs: pointer to the PSC's FIFO registers | |
79 | * @irq: IRQ of this PSC | |
80 | * @dev: struct device pointer | |
81 | * @dai: the CPU DAI for this device | |
82 | * @sicr: Base value used in serial interface control register; mode is ORed | |
83 | * with this value. | |
84 | * @playback: Playback stream context data | |
85 | * @capture: Capture stream context data | |
86 | */ | |
87 | struct psc_i2s { | |
88 | char name[32]; | |
89 | struct mpc52xx_psc __iomem *psc_regs; | |
90 | struct mpc52xx_psc_fifo __iomem *fifo_regs; | |
91 | unsigned int irq; | |
92 | struct device *dev; | |
93 | struct snd_soc_dai dai; | |
94 | spinlock_t lock; | |
95 | u32 sicr; | |
96 | ||
97 | /* per-stream data */ | |
98 | struct psc_i2s_stream playback; | |
99 | struct psc_i2s_stream capture; | |
100 | ||
101 | /* Statistics */ | |
102 | struct { | |
103 | int overrun_count; | |
104 | int underrun_count; | |
105 | } stats; | |
106 | }; | |
107 | ||
108 | /* | |
109 | * Interrupt handlers | |
110 | */ | |
111 | static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s) | |
112 | { | |
113 | struct psc_i2s *psc_i2s = _psc_i2s; | |
114 | struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; | |
115 | u16 isr; | |
116 | ||
117 | isr = in_be16(®s->mpc52xx_psc_isr); | |
118 | ||
119 | /* Playback underrun error */ | |
120 | if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) | |
121 | psc_i2s->stats.underrun_count++; | |
122 | ||
123 | /* Capture overrun error */ | |
124 | if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) | |
125 | psc_i2s->stats.overrun_count++; | |
126 | ||
127 | out_8(®s->command, 4 << 4); /* reset the error status */ | |
128 | ||
129 | return IRQ_HANDLED; | |
130 | } | |
131 | ||
132 | /** | |
133 | * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer | |
134 | * @s: pointer to stream private data structure | |
135 | * | |
136 | * Enqueues another audio period buffer into the bestcomm queue. | |
137 | * | |
138 | * Note: The routine must only be called when there is space available in | |
139 | * the queue. Otherwise the enqueue will fail and the audio ring buffer | |
140 | * will get out of sync | |
141 | */ | |
142 | static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s) | |
143 | { | |
144 | struct bcom_bd *bd; | |
145 | ||
146 | /* Prepare and enqueue the next buffer descriptor */ | |
147 | bd = bcom_prepare_next_buffer(s->bcom_task); | |
148 | bd->status = s->period_bytes; | |
149 | bd->data[0] = s->period_next_pt; | |
150 | bcom_submit_next_buffer(s->bcom_task, NULL); | |
151 | ||
152 | /* Update for next period */ | |
153 | s->period_next_pt += s->period_bytes; | |
154 | if (s->period_next_pt >= s->period_end) | |
155 | s->period_next_pt = s->period_start; | |
156 | } | |
157 | ||
158 | /* Bestcomm DMA irq handler */ | |
159 | static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) | |
160 | { | |
161 | struct psc_i2s_stream *s = _psc_i2s_stream; | |
162 | ||
163 | /* For each finished period, dequeue the completed period buffer | |
164 | * and enqueue a new one in it's place. */ | |
165 | while (bcom_buffer_done(s->bcom_task)) { | |
166 | bcom_retrieve_buffer(s->bcom_task, NULL, NULL); | |
167 | s->period_current_pt += s->period_bytes; | |
168 | if (s->period_current_pt >= s->period_end) | |
169 | s->period_current_pt = s->period_start; | |
170 | psc_i2s_bcom_enqueue_next_buffer(s); | |
171 | bcom_enable(s->bcom_task); | |
172 | } | |
173 | ||
174 | /* If the stream is active, then also inform the PCM middle layer | |
175 | * of the period finished event. */ | |
176 | if (s->active) | |
177 | snd_pcm_period_elapsed(s->stream); | |
178 | ||
179 | return IRQ_HANDLED; | |
180 | } | |
181 | ||
182 | /** | |
183 | * psc_i2s_startup: create a new substream | |
184 | * | |
185 | * This is the first function called when a stream is opened. | |
186 | * | |
187 | * If this is the first stream open, then grab the IRQ and program most of | |
188 | * the PSC registers. | |
189 | */ | |
dee89c4d MB |
190 | static int psc_i2s_startup(struct snd_pcm_substream *substream, |
191 | struct snd_soc_dai *dai) | |
dc641378 GL |
192 | { |
193 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
194 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | |
195 | int rc; | |
196 | ||
197 | dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream); | |
198 | ||
199 | if (!psc_i2s->playback.active && | |
200 | !psc_i2s->capture.active) { | |
201 | /* Setup the IRQs */ | |
202 | rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED, | |
203 | "psc-i2s-status", psc_i2s); | |
204 | rc |= request_irq(psc_i2s->capture.irq, | |
205 | &psc_i2s_bcom_irq, IRQF_SHARED, | |
206 | "psc-i2s-capture", &psc_i2s->capture); | |
207 | rc |= request_irq(psc_i2s->playback.irq, | |
208 | &psc_i2s_bcom_irq, IRQF_SHARED, | |
209 | "psc-i2s-playback", &psc_i2s->playback); | |
210 | if (rc) { | |
211 | free_irq(psc_i2s->irq, psc_i2s); | |
212 | free_irq(psc_i2s->capture.irq, | |
213 | &psc_i2s->capture); | |
214 | free_irq(psc_i2s->playback.irq, | |
215 | &psc_i2s->playback); | |
216 | return -ENODEV; | |
217 | } | |
218 | } | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | static int psc_i2s_hw_params(struct snd_pcm_substream *substream, | |
dee89c4d MB |
224 | struct snd_pcm_hw_params *params, |
225 | struct snd_soc_dai *dai) | |
dc641378 GL |
226 | { |
227 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
228 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | |
229 | u32 mode; | |
230 | ||
231 | dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i" | |
232 | " periods=%i buffer_size=%i buffer_bytes=%i\n", | |
233 | __func__, substream, params_period_size(params), | |
234 | params_period_bytes(params), params_periods(params), | |
235 | params_buffer_size(params), params_buffer_bytes(params)); | |
236 | ||
237 | switch (params_format(params)) { | |
238 | case SNDRV_PCM_FORMAT_S8: | |
239 | mode = MPC52xx_PSC_SICR_SIM_CODEC_8; | |
240 | break; | |
241 | case SNDRV_PCM_FORMAT_S16_BE: | |
242 | mode = MPC52xx_PSC_SICR_SIM_CODEC_16; | |
243 | break; | |
244 | case SNDRV_PCM_FORMAT_S24_BE: | |
245 | mode = MPC52xx_PSC_SICR_SIM_CODEC_24; | |
246 | break; | |
247 | case SNDRV_PCM_FORMAT_S32_BE: | |
248 | mode = MPC52xx_PSC_SICR_SIM_CODEC_32; | |
249 | break; | |
250 | default: | |
251 | dev_dbg(psc_i2s->dev, "invalid format\n"); | |
252 | return -EINVAL; | |
253 | } | |
254 | out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode); | |
255 | ||
256 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | |
257 | ||
258 | return 0; | |
259 | } | |
260 | ||
dee89c4d MB |
261 | static int psc_i2s_hw_free(struct snd_pcm_substream *substream, |
262 | struct snd_soc_dai *dai) | |
dc641378 GL |
263 | { |
264 | snd_pcm_set_runtime_buffer(substream, NULL); | |
265 | return 0; | |
266 | } | |
267 | ||
268 | /** | |
269 | * psc_i2s_trigger: start and stop the DMA transfer. | |
270 | * | |
271 | * This function is called by ALSA to start, stop, pause, and resume the DMA | |
272 | * transfer of data. | |
273 | */ | |
dee89c4d MB |
274 | static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, |
275 | struct snd_soc_dai *dai) | |
dc641378 GL |
276 | { |
277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
278 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | |
279 | struct snd_pcm_runtime *runtime = substream->runtime; | |
280 | struct psc_i2s_stream *s; | |
281 | struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; | |
282 | u16 imr; | |
283 | u8 psc_cmd; | |
f06c8fd7 | 284 | unsigned long flags; |
dc641378 GL |
285 | |
286 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | |
287 | s = &psc_i2s->capture; | |
288 | else | |
289 | s = &psc_i2s->playback; | |
290 | ||
291 | dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)" | |
292 | " stream_id=%i\n", | |
293 | substream, cmd, substream->pstr->stream); | |
294 | ||
295 | switch (cmd) { | |
296 | case SNDRV_PCM_TRIGGER_START: | |
297 | s->period_bytes = frames_to_bytes(runtime, | |
298 | runtime->period_size); | |
299 | s->period_start = virt_to_phys(runtime->dma_area); | |
300 | s->period_end = s->period_start + | |
301 | (s->period_bytes * runtime->periods); | |
302 | s->period_next_pt = s->period_start; | |
303 | s->period_current_pt = s->period_start; | |
304 | s->active = 1; | |
305 | ||
306 | /* First; reset everything */ | |
307 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { | |
308 | out_8(®s->command, MPC52xx_PSC_RST_RX); | |
309 | out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); | |
310 | } else { | |
311 | out_8(®s->command, MPC52xx_PSC_RST_TX); | |
312 | out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); | |
313 | } | |
314 | ||
315 | /* Next, fill up the bestcomm bd queue and enable DMA. | |
316 | * This will begin filling the PSC's fifo. */ | |
317 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | |
318 | bcom_gen_bd_rx_reset(s->bcom_task); | |
319 | else | |
320 | bcom_gen_bd_tx_reset(s->bcom_task); | |
321 | while (!bcom_queue_full(s->bcom_task)) | |
322 | psc_i2s_bcom_enqueue_next_buffer(s); | |
323 | bcom_enable(s->bcom_task); | |
324 | ||
325 | /* Due to errata in the i2s mode; need to line up enabling | |
326 | * the transmitter with a transition on the frame sync | |
327 | * line */ | |
328 | ||
329 | spin_lock_irqsave(&psc_i2s->lock, flags); | |
330 | /* first make sure it is low */ | |
331 | while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0) | |
332 | ; | |
333 | /* then wait for the transition to high */ | |
334 | while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0) | |
335 | ; | |
336 | /* Finally, enable the PSC. | |
337 | * Receiver must always be enabled; even when we only want | |
338 | * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */ | |
339 | psc_cmd = MPC52xx_PSC_RX_ENABLE; | |
340 | if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
341 | psc_cmd |= MPC52xx_PSC_TX_ENABLE; | |
342 | out_8(®s->command, psc_cmd); | |
343 | spin_unlock_irqrestore(&psc_i2s->lock, flags); | |
344 | ||
345 | break; | |
346 | ||
347 | case SNDRV_PCM_TRIGGER_STOP: | |
348 | /* Turn off the PSC */ | |
349 | s->active = 0; | |
350 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { | |
351 | if (!psc_i2s->playback.active) { | |
352 | out_8(®s->command, 2 << 4); /* reset rx */ | |
353 | out_8(®s->command, 3 << 4); /* reset tx */ | |
354 | out_8(®s->command, 4 << 4); /* reset err */ | |
355 | } | |
356 | } else { | |
357 | out_8(®s->command, 3 << 4); /* reset tx */ | |
358 | out_8(®s->command, 4 << 4); /* reset err */ | |
359 | if (!psc_i2s->capture.active) | |
360 | out_8(®s->command, 2 << 4); /* reset rx */ | |
361 | } | |
362 | ||
363 | bcom_disable(s->bcom_task); | |
364 | while (!bcom_queue_empty(s->bcom_task)) | |
365 | bcom_retrieve_buffer(s->bcom_task, NULL, NULL); | |
366 | ||
367 | break; | |
368 | ||
369 | default: | |
370 | dev_dbg(psc_i2s->dev, "invalid command\n"); | |
371 | return -EINVAL; | |
372 | } | |
373 | ||
374 | /* Update interrupt enable settings */ | |
375 | imr = 0; | |
376 | if (psc_i2s->playback.active) | |
377 | imr |= MPC52xx_PSC_IMR_TXEMP; | |
378 | if (psc_i2s->capture.active) | |
379 | imr |= MPC52xx_PSC_IMR_ORERR; | |
380 | out_be16(®s->isr_imr.imr, imr); | |
381 | ||
382 | return 0; | |
383 | } | |
384 | ||
385 | /** | |
386 | * psc_i2s_shutdown: shutdown the data transfer on a stream | |
387 | * | |
388 | * Shutdown the PSC if there are no other substreams open. | |
389 | */ | |
dee89c4d MB |
390 | static void psc_i2s_shutdown(struct snd_pcm_substream *substream, |
391 | struct snd_soc_dai *dai) | |
dc641378 GL |
392 | { |
393 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
394 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | |
395 | ||
396 | dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream); | |
397 | ||
398 | /* | |
399 | * If this is the last active substream, disable the PSC and release | |
400 | * the IRQ. | |
401 | */ | |
402 | if (!psc_i2s->playback.active && | |
403 | !psc_i2s->capture.active) { | |
404 | ||
405 | /* Disable all interrupts and reset the PSC */ | |
406 | out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); | |
407 | out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */ | |
408 | out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */ | |
409 | out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ | |
410 | out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ | |
411 | ||
412 | /* Release irqs */ | |
413 | free_irq(psc_i2s->irq, psc_i2s); | |
414 | free_irq(psc_i2s->capture.irq, &psc_i2s->capture); | |
415 | free_irq(psc_i2s->playback.irq, &psc_i2s->playback); | |
416 | } | |
417 | } | |
418 | ||
419 | /** | |
420 | * psc_i2s_set_sysclk: set the clock frequency and direction | |
421 | * | |
422 | * This function is called by the machine driver to tell us what the clock | |
423 | * frequency and direction are. | |
424 | * | |
425 | * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN), | |
426 | * and we don't care about the frequency. Return an error if the direction | |
427 | * is not SND_SOC_CLOCK_IN. | |
428 | * | |
429 | * @clk_id: reserved, should be zero | |
430 | * @freq: the frequency of the given clock ID, currently ignored | |
431 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) | |
432 | */ | |
433 | static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |
434 | int clk_id, unsigned int freq, int dir) | |
435 | { | |
436 | struct psc_i2s *psc_i2s = cpu_dai->private_data; | |
437 | dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n", | |
438 | cpu_dai, dir); | |
439 | return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL; | |
440 | } | |
441 | ||
442 | /** | |
443 | * psc_i2s_set_fmt: set the serial format. | |
444 | * | |
445 | * This function is called by the machine driver to tell us what serial | |
446 | * format to use. | |
447 | * | |
448 | * This driver only supports I2S mode. Return an error if the format is | |
449 | * not SND_SOC_DAIFMT_I2S. | |
450 | * | |
451 | * @format: one of SND_SOC_DAIFMT_xxx | |
452 | */ | |
453 | static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) | |
454 | { | |
455 | struct psc_i2s *psc_i2s = cpu_dai->private_data; | |
456 | dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n", | |
457 | cpu_dai, format); | |
458 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; | |
459 | } | |
460 | ||
461 | /* --------------------------------------------------------------------- | |
462 | * ALSA SoC Bindings | |
463 | * | |
464 | * - Digital Audio Interface (DAI) template | |
465 | * - create/destroy dai hooks | |
466 | */ | |
467 | ||
468 | /** | |
469 | * psc_i2s_dai_template: template CPU Digital Audio Interface | |
470 | */ | |
471 | static struct snd_soc_dai psc_i2s_dai_template = { | |
dc641378 GL |
472 | .playback = { |
473 | .channels_min = 2, | |
474 | .channels_max = 2, | |
475 | .rates = PSC_I2S_RATES, | |
476 | .formats = PSC_I2S_FORMATS, | |
477 | }, | |
478 | .capture = { | |
479 | .channels_min = 2, | |
480 | .channels_max = 2, | |
481 | .rates = PSC_I2S_RATES, | |
482 | .formats = PSC_I2S_FORMATS, | |
483 | }, | |
484 | .ops = { | |
485 | .startup = psc_i2s_startup, | |
486 | .hw_params = psc_i2s_hw_params, | |
487 | .hw_free = psc_i2s_hw_free, | |
488 | .shutdown = psc_i2s_shutdown, | |
489 | .trigger = psc_i2s_trigger, | |
dc641378 GL |
490 | .set_sysclk = psc_i2s_set_sysclk, |
491 | .set_fmt = psc_i2s_set_fmt, | |
492 | }, | |
493 | }; | |
494 | ||
495 | /* --------------------------------------------------------------------- | |
496 | * The PSC I2S 'ASoC platform' driver | |
497 | * | |
498 | * Can be referenced by an 'ASoC machine' driver | |
499 | * This driver only deals with the audio bus; it doesn't have any | |
500 | * interaction with the attached codec | |
501 | */ | |
502 | ||
503 | static const struct snd_pcm_hardware psc_i2s_pcm_hardware = { | |
504 | .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | |
505 | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER, | |
506 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | | |
507 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, | |
508 | .rate_min = 8000, | |
509 | .rate_max = 48000, | |
510 | .channels_min = 2, | |
511 | .channels_max = 2, | |
512 | .period_bytes_max = 1024 * 1024, | |
513 | .period_bytes_min = 32, | |
514 | .periods_min = 2, | |
515 | .periods_max = 256, | |
516 | .buffer_bytes_max = 2 * 1024 * 1024, | |
517 | .fifo_size = 0, | |
518 | }; | |
519 | ||
520 | static int psc_i2s_pcm_open(struct snd_pcm_substream *substream) | |
521 | { | |
522 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
523 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | |
524 | struct psc_i2s_stream *s; | |
525 | ||
526 | dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream); | |
527 | ||
528 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | |
529 | s = &psc_i2s->capture; | |
530 | else | |
531 | s = &psc_i2s->playback; | |
532 | ||
533 | snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware); | |
534 | ||
535 | s->stream = substream; | |
536 | return 0; | |
537 | } | |
538 | ||
539 | static int psc_i2s_pcm_close(struct snd_pcm_substream *substream) | |
540 | { | |
541 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
542 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | |
543 | struct psc_i2s_stream *s; | |
544 | ||
545 | dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream); | |
546 | ||
547 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | |
548 | s = &psc_i2s->capture; | |
549 | else | |
550 | s = &psc_i2s->playback; | |
551 | ||
552 | s->stream = NULL; | |
553 | return 0; | |
554 | } | |
555 | ||
556 | static snd_pcm_uframes_t | |
557 | psc_i2s_pcm_pointer(struct snd_pcm_substream *substream) | |
558 | { | |
559 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
560 | struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; | |
561 | struct psc_i2s_stream *s; | |
562 | dma_addr_t count; | |
563 | ||
564 | if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) | |
565 | s = &psc_i2s->capture; | |
566 | else | |
567 | s = &psc_i2s->playback; | |
568 | ||
569 | count = s->period_current_pt - s->period_start; | |
570 | ||
571 | return bytes_to_frames(substream->runtime, count); | |
572 | } | |
573 | ||
574 | static struct snd_pcm_ops psc_i2s_pcm_ops = { | |
575 | .open = psc_i2s_pcm_open, | |
576 | .close = psc_i2s_pcm_close, | |
577 | .ioctl = snd_pcm_lib_ioctl, | |
578 | .pointer = psc_i2s_pcm_pointer, | |
579 | }; | |
580 | ||
581 | static u64 psc_i2s_pcm_dmamask = 0xffffffff; | |
582 | static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | |
583 | struct snd_pcm *pcm) | |
584 | { | |
585 | struct snd_soc_pcm_runtime *rtd = pcm->private_data; | |
586 | size_t size = psc_i2s_pcm_hardware.buffer_bytes_max; | |
587 | int rc = 0; | |
588 | ||
589 | dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n", | |
590 | card, dai, pcm); | |
591 | ||
592 | if (!card->dev->dma_mask) | |
593 | card->dev->dma_mask = &psc_i2s_pcm_dmamask; | |
594 | if (!card->dev->coherent_dma_mask) | |
595 | card->dev->coherent_dma_mask = 0xffffffff; | |
596 | ||
597 | if (pcm->streams[0].substream) { | |
598 | rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, | |
599 | &pcm->streams[0].substream->dma_buffer); | |
600 | if (rc) | |
601 | goto playback_alloc_err; | |
602 | } | |
603 | ||
604 | if (pcm->streams[1].substream) { | |
605 | rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, | |
606 | &pcm->streams[1].substream->dma_buffer); | |
607 | if (rc) | |
608 | goto capture_alloc_err; | |
609 | } | |
610 | ||
611 | return 0; | |
612 | ||
613 | capture_alloc_err: | |
614 | if (pcm->streams[0].substream) | |
615 | snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); | |
616 | playback_alloc_err: | |
617 | dev_err(card->dev, "Cannot allocate buffer(s)\n"); | |
618 | return -ENOMEM; | |
619 | } | |
620 | ||
621 | static void psc_i2s_pcm_free(struct snd_pcm *pcm) | |
622 | { | |
623 | struct snd_soc_pcm_runtime *rtd = pcm->private_data; | |
624 | struct snd_pcm_substream *substream; | |
625 | int stream; | |
626 | ||
627 | dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm); | |
628 | ||
629 | for (stream = 0; stream < 2; stream++) { | |
630 | substream = pcm->streams[stream].substream; | |
631 | if (substream) { | |
632 | snd_dma_free_pages(&substream->dma_buffer); | |
633 | substream->dma_buffer.area = NULL; | |
634 | substream->dma_buffer.addr = 0; | |
635 | } | |
636 | } | |
637 | } | |
638 | ||
639 | struct snd_soc_platform psc_i2s_pcm_soc_platform = { | |
640 | .name = "mpc5200-psc-audio", | |
641 | .pcm_ops = &psc_i2s_pcm_ops, | |
642 | .pcm_new = &psc_i2s_pcm_new, | |
643 | .pcm_free = &psc_i2s_pcm_free, | |
644 | }; | |
645 | ||
646 | /* --------------------------------------------------------------------- | |
647 | * Sysfs attributes for debugging | |
648 | */ | |
649 | ||
650 | static ssize_t psc_i2s_status_show(struct device *dev, | |
651 | struct device_attribute *attr, char *buf) | |
652 | { | |
653 | struct psc_i2s *psc_i2s = dev_get_drvdata(dev); | |
654 | ||
655 | return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x " | |
656 | "tfnum=%i tfstat=0x%.4x\n", | |
657 | in_be16(&psc_i2s->psc_regs->sr_csr.status), | |
658 | in_be32(&psc_i2s->psc_regs->sicr), | |
659 | in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff, | |
660 | in_be16(&psc_i2s->fifo_regs->rfstat), | |
661 | in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff, | |
662 | in_be16(&psc_i2s->fifo_regs->tfstat)); | |
663 | } | |
664 | ||
665 | static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name) | |
666 | { | |
667 | if (strcmp(name, "playback_underrun") == 0) | |
668 | return &psc_i2s->stats.underrun_count; | |
669 | if (strcmp(name, "capture_overrun") == 0) | |
670 | return &psc_i2s->stats.overrun_count; | |
671 | ||
672 | return NULL; | |
673 | } | |
674 | ||
675 | static ssize_t psc_i2s_stat_show(struct device *dev, | |
676 | struct device_attribute *attr, char *buf) | |
677 | { | |
678 | struct psc_i2s *psc_i2s = dev_get_drvdata(dev); | |
679 | int *attrib; | |
680 | ||
681 | attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); | |
682 | if (!attrib) | |
683 | return 0; | |
684 | ||
685 | return sprintf(buf, "%i\n", *attrib); | |
686 | } | |
687 | ||
688 | static ssize_t psc_i2s_stat_store(struct device *dev, | |
689 | struct device_attribute *attr, | |
690 | const char *buf, | |
691 | size_t count) | |
692 | { | |
693 | struct psc_i2s *psc_i2s = dev_get_drvdata(dev); | |
694 | int *attrib; | |
695 | ||
696 | attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); | |
697 | if (!attrib) | |
698 | return 0; | |
699 | ||
700 | *attrib = simple_strtoul(buf, NULL, 0); | |
701 | return count; | |
702 | } | |
703 | ||
f06c8fd7 JS |
704 | static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL); |
705 | static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show, | |
706 | psc_i2s_stat_store); | |
707 | static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, | |
708 | psc_i2s_stat_store); | |
dc641378 GL |
709 | |
710 | /* --------------------------------------------------------------------- | |
711 | * OF platform bus binding code: | |
712 | * - Probe/remove operations | |
713 | * - OF device match table | |
714 | */ | |
715 | static int __devinit psc_i2s_of_probe(struct of_device *op, | |
716 | const struct of_device_id *match) | |
717 | { | |
718 | phys_addr_t fifo; | |
719 | struct psc_i2s *psc_i2s; | |
720 | struct resource res; | |
721 | int size, psc_id, irq, rc; | |
722 | const __be32 *prop; | |
723 | void __iomem *regs; | |
724 | ||
725 | dev_dbg(&op->dev, "probing psc i2s device\n"); | |
726 | ||
727 | /* Get the PSC ID */ | |
728 | prop = of_get_property(op->node, "cell-index", &size); | |
729 | if (!prop || size < sizeof *prop) | |
730 | return -ENODEV; | |
731 | psc_id = be32_to_cpu(*prop); | |
732 | ||
733 | /* Fetch the registers and IRQ of the PSC */ | |
734 | irq = irq_of_parse_and_map(op->node, 0); | |
735 | if (of_address_to_resource(op->node, 0, &res)) { | |
736 | dev_err(&op->dev, "Missing reg property\n"); | |
737 | return -ENODEV; | |
738 | } | |
739 | regs = ioremap(res.start, 1 + res.end - res.start); | |
740 | if (!regs) { | |
741 | dev_err(&op->dev, "Could not map registers\n"); | |
742 | return -ENODEV; | |
743 | } | |
744 | ||
745 | /* Allocate and initialize the driver private data */ | |
746 | psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL); | |
747 | if (!psc_i2s) { | |
748 | iounmap(regs); | |
749 | return -ENOMEM; | |
750 | } | |
751 | spin_lock_init(&psc_i2s->lock); | |
752 | psc_i2s->irq = irq; | |
753 | psc_i2s->psc_regs = regs; | |
754 | psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs; | |
755 | psc_i2s->dev = &op->dev; | |
756 | psc_i2s->playback.psc_i2s = psc_i2s; | |
757 | psc_i2s->capture.psc_i2s = psc_i2s; | |
758 | snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1); | |
759 | ||
760 | /* Fill out the CPU DAI structure */ | |
761 | memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai); | |
762 | psc_i2s->dai.private_data = psc_i2s; | |
763 | psc_i2s->dai.name = psc_i2s->name; | |
764 | psc_i2s->dai.id = psc_id; | |
765 | ||
766 | /* Find the address of the fifo data registers and setup the | |
767 | * DMA tasks */ | |
768 | fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); | |
769 | psc_i2s->capture.bcom_task = | |
770 | bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512); | |
771 | psc_i2s->playback.bcom_task = | |
772 | bcom_psc_gen_bd_tx_init(psc_id, 10, fifo); | |
773 | if (!psc_i2s->capture.bcom_task || | |
774 | !psc_i2s->playback.bcom_task) { | |
775 | dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); | |
776 | iounmap(regs); | |
777 | kfree(psc_i2s); | |
778 | return -ENODEV; | |
779 | } | |
780 | ||
781 | /* Disable all interrupts and reset the PSC */ | |
782 | out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); | |
783 | out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */ | |
784 | out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */ | |
785 | out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ | |
786 | out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ | |
787 | ||
788 | /* Configure the serial interface mode; defaulting to CODEC8 mode */ | |
789 | psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S | | |
790 | MPC52xx_PSC_SICR_CLKPOL; | |
791 | if (of_get_property(op->node, "fsl,cellslave", NULL)) | |
792 | psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE | | |
793 | MPC52xx_PSC_SICR_GENCLK; | |
794 | out_be32(&psc_i2s->psc_regs->sicr, | |
795 | psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8); | |
796 | ||
797 | /* Check for the codec handle. If it is not present then we | |
798 | * are done */ | |
799 | if (!of_get_property(op->node, "codec-handle", NULL)) | |
800 | return 0; | |
801 | ||
802 | /* Set up mode register; | |
803 | * First write: RxRdy (FIFO Alarm) generates rx FIFO irq | |
804 | * Second write: register Normal mode for non loopback | |
805 | */ | |
806 | out_8(&psc_i2s->psc_regs->mode, 0); | |
807 | out_8(&psc_i2s->psc_regs->mode, 0); | |
808 | ||
809 | /* Set the TX and RX fifo alarm thresholds */ | |
810 | out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100); | |
811 | out_8(&psc_i2s->fifo_regs->rfcntl, 0x4); | |
812 | out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100); | |
813 | out_8(&psc_i2s->fifo_regs->tfcntl, 0x7); | |
814 | ||
815 | /* Lookup the IRQ numbers */ | |
816 | psc_i2s->playback.irq = | |
817 | bcom_get_task_irq(psc_i2s->playback.bcom_task); | |
818 | psc_i2s->capture.irq = | |
819 | bcom_get_task_irq(psc_i2s->capture.bcom_task); | |
820 | ||
821 | /* Save what we've done so it can be found again later */ | |
822 | dev_set_drvdata(&op->dev, psc_i2s); | |
823 | ||
824 | /* Register the SYSFS files */ | |
825 | rc = device_create_file(psc_i2s->dev, &dev_attr_status); | |
f06c8fd7 JS |
826 | rc |= device_create_file(psc_i2s->dev, &dev_attr_capture_overrun); |
827 | rc |= device_create_file(psc_i2s->dev, &dev_attr_playback_underrun); | |
dc641378 GL |
828 | if (rc) |
829 | dev_info(psc_i2s->dev, "error creating sysfs files\n"); | |
830 | ||
958e792c MB |
831 | snd_soc_register_platform(&psc_i2s_pcm_soc_platform); |
832 | ||
dc641378 GL |
833 | /* Tell the ASoC OF helpers about it */ |
834 | of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, | |
835 | &psc_i2s->dai); | |
836 | ||
837 | return 0; | |
838 | } | |
839 | ||
840 | static int __devexit psc_i2s_of_remove(struct of_device *op) | |
841 | { | |
842 | struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev); | |
843 | ||
844 | dev_dbg(&op->dev, "psc_i2s_remove()\n"); | |
845 | ||
958e792c MB |
846 | snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform); |
847 | ||
dc641378 GL |
848 | bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); |
849 | bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); | |
850 | ||
851 | iounmap(psc_i2s->psc_regs); | |
852 | iounmap(psc_i2s->fifo_regs); | |
853 | kfree(psc_i2s); | |
854 | dev_set_drvdata(&op->dev, NULL); | |
855 | ||
856 | return 0; | |
857 | } | |
858 | ||
859 | /* Match table for of_platform binding */ | |
860 | static struct of_device_id psc_i2s_match[] __devinitdata = { | |
861 | { .compatible = "fsl,mpc5200-psc-i2s", }, | |
862 | {} | |
863 | }; | |
864 | MODULE_DEVICE_TABLE(of, psc_i2s_match); | |
865 | ||
866 | static struct of_platform_driver psc_i2s_driver = { | |
867 | .match_table = psc_i2s_match, | |
868 | .probe = psc_i2s_of_probe, | |
869 | .remove = __devexit_p(psc_i2s_of_remove), | |
870 | .driver = { | |
871 | .name = "mpc5200-psc-i2s", | |
872 | .owner = THIS_MODULE, | |
873 | }, | |
874 | }; | |
875 | ||
876 | /* --------------------------------------------------------------------- | |
877 | * Module setup and teardown; simply register the of_platform driver | |
878 | * for the PSC in I2S mode. | |
879 | */ | |
880 | static int __init psc_i2s_init(void) | |
881 | { | |
882 | return of_register_platform_driver(&psc_i2s_driver); | |
883 | } | |
884 | module_init(psc_i2s_init); | |
885 | ||
886 | static void __exit psc_i2s_exit(void) | |
887 | { | |
888 | of_unregister_platform_driver(&psc_i2s_driver); | |
889 | } | |
890 | module_exit(psc_i2s_exit); | |
891 | ||
892 |