diff options
Diffstat (limited to 'sound/ppc/snd_ps3.c')
-rw-r--r-- | sound/ppc/snd_ps3.c | 1125 |
1 files changed, 1125 insertions, 0 deletions
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c new file mode 100644 index 000000000000..1aa0b467599f --- /dev/null +++ b/sound/ppc/snd_ps3.c | |||
@@ -0,0 +1,1125 @@ | |||
1 | /* | ||
2 | * Audio support for PS3 | ||
3 | * Copyright (C) 2007 Sony Computer Entertainment Inc. | ||
4 | * All rights reserved. | ||
5 | * Copyright 2006, 2007 Sony Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; version 2 of the Licence. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/asound.h> | ||
30 | #include <sound/memalloc.h> | ||
31 | #include <sound/pcm_params.h> | ||
32 | #include <sound/control.h> | ||
33 | #include <linux/dmapool.h> | ||
34 | #include <linux/dma-mapping.h> | ||
35 | #include <asm/firmware.h> | ||
36 | #include <linux/io.h> | ||
37 | #include <asm/dma.h> | ||
38 | #include <asm/lv1call.h> | ||
39 | #include <asm/ps3.h> | ||
40 | #include <asm/ps3av.h> | ||
41 | |||
42 | #include "snd_ps3_reg.h" | ||
43 | #include "snd_ps3.h" | ||
44 | |||
45 | MODULE_LICENSE("GPL v2"); | ||
46 | MODULE_DESCRIPTION("PS3 sound driver"); | ||
47 | MODULE_AUTHOR("Sony Computer Entertainment Inc."); | ||
48 | |||
49 | /* module entries */ | ||
50 | static int __init snd_ps3_init(void); | ||
51 | static void __exit snd_ps3_exit(void); | ||
52 | |||
53 | /* ALSA snd driver ops */ | ||
54 | static int snd_ps3_pcm_open(struct snd_pcm_substream *substream); | ||
55 | static int snd_ps3_pcm_close(struct snd_pcm_substream *substream); | ||
56 | static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream); | ||
57 | static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, | ||
58 | int cmd); | ||
59 | static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream | ||
60 | *substream); | ||
61 | static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, | ||
62 | struct snd_pcm_hw_params *hw_params); | ||
63 | static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream); | ||
64 | |||
65 | |||
66 | /* ps3_system_bus_driver entries */ | ||
67 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev); | ||
68 | static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev); | ||
69 | |||
70 | /* address setup */ | ||
71 | static int snd_ps3_map_mmio(void); | ||
72 | static void snd_ps3_unmap_mmio(void); | ||
73 | static int snd_ps3_allocate_irq(void); | ||
74 | static void snd_ps3_free_irq(void); | ||
75 | static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start); | ||
76 | |||
77 | /* interrupt handler */ | ||
78 | static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id); | ||
79 | |||
80 | |||
81 | /* set sampling rate/format */ | ||
82 | static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream); | ||
83 | /* take effect parameter change */ | ||
84 | static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card); | ||
85 | /* initialize avsetting and take it effect */ | ||
86 | static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card); | ||
87 | /* setup dma */ | ||
88 | static int snd_ps3_program_dma(struct snd_ps3_card_info *card, | ||
89 | enum snd_ps3_dma_filltype filltype); | ||
90 | static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card); | ||
91 | |||
92 | static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void *vaddr, int ch); | ||
93 | |||
94 | |||
95 | module_init(snd_ps3_init); | ||
96 | module_exit(snd_ps3_exit); | ||
97 | |||
98 | /* | ||
99 | * global | ||
100 | */ | ||
101 | static struct snd_ps3_card_info the_card; | ||
102 | |||
103 | static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY; | ||
104 | |||
105 | module_param_named(start_delay, snd_ps3_start_delay, uint, 0644); | ||
106 | MODULE_PARM_DESC(start_delay, "time to insert silent data in milisec"); | ||
107 | |||
108 | static int index = SNDRV_DEFAULT_IDX1; | ||
109 | static char *id = SNDRV_DEFAULT_STR1; | ||
110 | |||
111 | module_param(index, int, 0444); | ||
112 | MODULE_PARM_DESC(index, "Index value for PS3 soundchip."); | ||
113 | module_param(id, charp, 0444); | ||
114 | MODULE_PARM_DESC(id, "ID string for PS3 soundchip."); | ||
115 | |||
116 | |||
117 | /* | ||
118 | * PS3 audio register access | ||
119 | */ | ||
120 | static inline u32 read_reg(unsigned int reg) | ||
121 | { | ||
122 | return in_be32(the_card.mapped_mmio_vaddr + reg); | ||
123 | } | ||
124 | static inline void write_reg(unsigned int reg, u32 val) | ||
125 | { | ||
126 | out_be32(the_card.mapped_mmio_vaddr + reg, val); | ||
127 | } | ||
128 | static inline void update_reg(unsigned int reg, u32 or_val) | ||
129 | { | ||
130 | u32 newval = read_reg(reg) | or_val; | ||
131 | write_reg(reg, newval); | ||
132 | } | ||
133 | static inline void update_mask_reg(unsigned int reg, u32 mask, u32 or_val) | ||
134 | { | ||
135 | u32 newval = (read_reg(reg) & mask) | or_val; | ||
136 | write_reg(reg, newval); | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * ALSA defs | ||
141 | */ | ||
142 | const static struct snd_pcm_hardware snd_ps3_pcm_hw = { | ||
143 | .info = (SNDRV_PCM_INFO_MMAP | | ||
144 | SNDRV_PCM_INFO_NONINTERLEAVED | | ||
145 | SNDRV_PCM_INFO_MMAP_VALID), | ||
146 | .formats = (SNDRV_PCM_FMTBIT_S16_BE | | ||
147 | SNDRV_PCM_FMTBIT_S24_BE), | ||
148 | .rates = (SNDRV_PCM_RATE_44100 | | ||
149 | SNDRV_PCM_RATE_48000 | | ||
150 | SNDRV_PCM_RATE_88200 | | ||
151 | SNDRV_PCM_RATE_96000), | ||
152 | .rate_min = 44100, | ||
153 | .rate_max = 96000, | ||
154 | |||
155 | .channels_min = 2, /* stereo only */ | ||
156 | .channels_max = 2, | ||
157 | |||
158 | .buffer_bytes_max = PS3_AUDIO_FIFO_SIZE * 64, | ||
159 | |||
160 | /* interrupt by four stages */ | ||
161 | .period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4, | ||
162 | .period_bytes_max = PS3_AUDIO_FIFO_STAGE_SIZE * 4, | ||
163 | |||
164 | .periods_min = 16, | ||
165 | .periods_max = 32, /* buffer_size_max/ period_bytes_max */ | ||
166 | |||
167 | .fifo_size = PS3_AUDIO_FIFO_SIZE | ||
168 | }; | ||
169 | |||
170 | static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = | ||
171 | { | ||
172 | .open = snd_ps3_pcm_open, | ||
173 | .close = snd_ps3_pcm_close, | ||
174 | .prepare = snd_ps3_pcm_prepare, | ||
175 | .ioctl = snd_pcm_lib_ioctl, | ||
176 | .trigger = snd_ps3_pcm_trigger, | ||
177 | .pointer = snd_ps3_pcm_pointer, | ||
178 | .hw_params = snd_ps3_pcm_hw_params, | ||
179 | .hw_free = snd_ps3_pcm_hw_free | ||
180 | }; | ||
181 | |||
182 | static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card, | ||
183 | int count, int force_stop) | ||
184 | { | ||
185 | int dma_ch, done, retries, stop_forced = 0; | ||
186 | uint32_t status; | ||
187 | |||
188 | for (dma_ch = 0; dma_ch < 8; dma_ch ++) { | ||
189 | retries = count; | ||
190 | do { | ||
191 | status = read_reg(PS3_AUDIO_KICK(dma_ch)) & | ||
192 | PS3_AUDIO_KICK_STATUS_MASK; | ||
193 | switch (status) { | ||
194 | case PS3_AUDIO_KICK_STATUS_DONE: | ||
195 | case PS3_AUDIO_KICK_STATUS_NOTIFY: | ||
196 | case PS3_AUDIO_KICK_STATUS_CLEAR: | ||
197 | case PS3_AUDIO_KICK_STATUS_ERROR: | ||
198 | done = 1; | ||
199 | break; | ||
200 | default: | ||
201 | done = 0; | ||
202 | udelay(10); | ||
203 | } | ||
204 | } while (!done && --retries); | ||
205 | if (!retries && force_stop) { | ||
206 | pr_info("%s: DMA ch %d is not stopped.", | ||
207 | __func__, dma_ch); | ||
208 | /* last resort. force to stop dma. | ||
209 | * NOTE: this cause DMA done interrupts | ||
210 | */ | ||
211 | update_reg(PS3_AUDIO_CONFIG, PS3_AUDIO_CONFIG_CLEAR); | ||
212 | stop_forced = 1; | ||
213 | } | ||
214 | } | ||
215 | return stop_forced; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * wait for all dma is done. | ||
220 | * NOTE: caller should reset card->running before call. | ||
221 | * If not, the interrupt handler will re-start DMA, | ||
222 | * then DMA is never stopped. | ||
223 | */ | ||
224 | static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card) | ||
225 | { | ||
226 | int stop_forced; | ||
227 | /* | ||
228 | * wait for the last dma is done | ||
229 | */ | ||
230 | |||
231 | /* | ||
232 | * expected maximum DMA done time is 5.7ms + something (DMA itself). | ||
233 | * 5.7ms is from 16bit/sample 2ch 44.1Khz; the time next | ||
234 | * DMA kick event would occur. | ||
235 | */ | ||
236 | stop_forced = snd_ps3_verify_dma_stop(card, 700, 1); | ||
237 | |||
238 | /* | ||
239 | * clear outstanding interrupts. | ||
240 | */ | ||
241 | update_reg(PS3_AUDIO_INTR_0, 0); | ||
242 | update_reg(PS3_AUDIO_AX_IS, 0); | ||
243 | |||
244 | /* | ||
245 | *revert CLEAR bit since it will not reset automatically after DMA stop | ||
246 | */ | ||
247 | if (stop_forced) | ||
248 | update_mask_reg(PS3_AUDIO_CONFIG, ~PS3_AUDIO_CONFIG_CLEAR, 0); | ||
249 | /* ensure the hardware sees changes */ | ||
250 | wmb(); | ||
251 | } | ||
252 | |||
253 | static void snd_ps3_kick_dma(struct snd_ps3_card_info *card) | ||
254 | { | ||
255 | |||
256 | update_reg(PS3_AUDIO_KICK(0), PS3_AUDIO_KICK_REQUEST); | ||
257 | /* ensure the hardware sees the change */ | ||
258 | wmb(); | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * convert virtual addr to ioif bus addr. | ||
263 | */ | ||
264 | static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, | ||
265 | void * paddr, | ||
266 | int ch) | ||
267 | { | ||
268 | return card->dma_start_bus_addr[ch] + | ||
269 | (paddr - card->dma_start_vaddr[ch]); | ||
270 | }; | ||
271 | |||
272 | |||
273 | /* | ||
274 | * increment ring buffer pointer. | ||
275 | * NOTE: caller must hold write spinlock | ||
276 | */ | ||
277 | static void snd_ps3_bump_buffer(struct snd_ps3_card_info *card, | ||
278 | enum snd_ps3_ch ch, size_t byte_count, | ||
279 | int stage) | ||
280 | { | ||
281 | if (!stage) | ||
282 | card->dma_last_transfer_vaddr[ch] = | ||
283 | card->dma_next_transfer_vaddr[ch]; | ||
284 | card->dma_next_transfer_vaddr[ch] += byte_count; | ||
285 | if ((card->dma_start_vaddr[ch] + (card->dma_buffer_size / 2)) <= | ||
286 | card->dma_next_transfer_vaddr[ch]) { | ||
287 | card->dma_next_transfer_vaddr[ch] = card->dma_start_vaddr[ch]; | ||
288 | } | ||
289 | } | ||
290 | /* | ||
291 | * setup dmac to send data to audio and attenuate samples on the ring buffer | ||
292 | */ | ||
293 | static int snd_ps3_program_dma(struct snd_ps3_card_info *card, | ||
294 | enum snd_ps3_dma_filltype filltype) | ||
295 | { | ||
296 | /* this dmac does not support over 4G */ | ||
297 | uint32_t dma_addr; | ||
298 | int fill_stages, dma_ch, stage; | ||
299 | enum snd_ps3_ch ch; | ||
300 | uint32_t ch0_kick_event = 0; /* initialize to mute gcc */ | ||
301 | void *start_vaddr; | ||
302 | unsigned long irqsave; | ||
303 | int silent = 0; | ||
304 | |||
305 | switch (filltype) { | ||
306 | case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL: | ||
307 | silent = 1; | ||
308 | /* intentionally fall thru */ | ||
309 | case SND_PS3_DMA_FILLTYPE_FIRSTFILL: | ||
310 | ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS; | ||
311 | break; | ||
312 | |||
313 | case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING: | ||
314 | silent = 1; | ||
315 | /* intentionally fall thru */ | ||
316 | case SND_PS3_DMA_FILLTYPE_RUNNING: | ||
317 | ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY; | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | snd_ps3_verify_dma_stop(card, 700, 0); | ||
322 | fill_stages = 4; | ||
323 | spin_lock_irqsave(&card->dma_lock, irqsave); | ||
324 | for (ch = 0; ch < 2; ch++) { | ||
325 | start_vaddr = card->dma_next_transfer_vaddr[0]; | ||
326 | for (stage = 0; stage < fill_stages; stage ++) { | ||
327 | dma_ch = stage * 2 + ch; | ||
328 | if (silent) | ||
329 | dma_addr = card->null_buffer_start_dma_addr; | ||
330 | else | ||
331 | dma_addr = | ||
332 | v_to_bus(card, | ||
333 | card->dma_next_transfer_vaddr[ch], | ||
334 | ch); | ||
335 | |||
336 | write_reg(PS3_AUDIO_SOURCE(dma_ch), | ||
337 | (PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY | | ||
338 | dma_addr)); | ||
339 | |||
340 | /* dst: fixed to 3wire#0 */ | ||
341 | if (ch == 0) | ||
342 | write_reg(PS3_AUDIO_DEST(dma_ch), | ||
343 | (PS3_AUDIO_DEST_TARGET_AUDIOFIFO | | ||
344 | PS3_AUDIO_AO_3W_LDATA(0))); | ||
345 | else | ||
346 | write_reg(PS3_AUDIO_DEST(dma_ch), | ||
347 | (PS3_AUDIO_DEST_TARGET_AUDIOFIFO | | ||
348 | PS3_AUDIO_AO_3W_RDATA(0))); | ||
349 | |||
350 | /* count always 1 DMA block (1/2 stage = 128 bytes) */ | ||
351 | write_reg(PS3_AUDIO_DMASIZE(dma_ch), 0); | ||
352 | /* bump pointer if needed */ | ||
353 | if (!silent) | ||
354 | snd_ps3_bump_buffer(card, ch, | ||
355 | PS3_AUDIO_DMAC_BLOCK_SIZE, | ||
356 | stage); | ||
357 | |||
358 | /* kick event */ | ||
359 | if (dma_ch == 0) | ||
360 | write_reg(PS3_AUDIO_KICK(dma_ch), | ||
361 | ch0_kick_event); | ||
362 | else | ||
363 | write_reg(PS3_AUDIO_KICK(dma_ch), | ||
364 | PS3_AUDIO_KICK_EVENT_AUDIO_DMA(dma_ch | ||
365 | - 1) | | ||
366 | PS3_AUDIO_KICK_REQUEST); | ||
367 | } | ||
368 | } | ||
369 | /* ensure the hardware sees the change */ | ||
370 | wmb(); | ||
371 | spin_unlock_irqrestore(&card->dma_lock, irqsave); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * audio mute on/off | ||
378 | * mute_on : 0 output enabled | ||
379 | * 1 mute | ||
380 | */ | ||
381 | static int snd_ps3_mute(int mute_on) | ||
382 | { | ||
383 | return ps3av_audio_mute(mute_on); | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * PCM operators | ||
388 | */ | ||
389 | static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) | ||
390 | { | ||
391 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
392 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | ||
393 | int pcm_index; | ||
394 | |||
395 | pcm_index = substream->pcm->device; | ||
396 | /* to retrieve substream/runtime in interrupt handler */ | ||
397 | card->substream = substream; | ||
398 | |||
399 | runtime->hw = snd_ps3_pcm_hw; | ||
400 | |||
401 | card->start_delay = snd_ps3_start_delay; | ||
402 | |||
403 | /* mute off */ | ||
404 | snd_ps3_mute(0); /* this function sleep */ | ||
405 | |||
406 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
407 | PS3_AUDIO_FIFO_STAGE_SIZE * 4 * 2); | ||
408 | return 0; | ||
409 | }; | ||
410 | |||
411 | static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, | ||
412 | struct snd_pcm_hw_params *hw_params) | ||
413 | { | ||
414 | size_t size; | ||
415 | |||
416 | /* alloc transport buffer */ | ||
417 | size = params_buffer_bytes(hw_params); | ||
418 | snd_pcm_lib_malloc_pages(substream, size); | ||
419 | return 0; | ||
420 | }; | ||
421 | |||
422 | static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, | ||
423 | unsigned int delay_ms) | ||
424 | { | ||
425 | int ret; | ||
426 | int rate ; | ||
427 | |||
428 | rate = substream->runtime->rate; | ||
429 | ret = snd_pcm_format_size(substream->runtime->format, | ||
430 | rate * delay_ms / 1000) | ||
431 | * substream->runtime->channels; | ||
432 | |||
433 | pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n", | ||
434 | __func__, | ||
435 | delay_ms, | ||
436 | rate, | ||
437 | snd_pcm_format_size(substream->runtime->format, rate), | ||
438 | rate * delay_ms / 1000, | ||
439 | ret); | ||
440 | |||
441 | return ret; | ||
442 | }; | ||
443 | |||
444 | static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream) | ||
445 | { | ||
446 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
447 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | ||
448 | unsigned long irqsave; | ||
449 | |||
450 | if (!snd_ps3_set_avsetting(substream)) { | ||
451 | /* some parameter changed */ | ||
452 | write_reg(PS3_AUDIO_AX_IE, | ||
453 | PS3_AUDIO_AX_IE_ASOBEIE(0) | | ||
454 | PS3_AUDIO_AX_IE_ASOBUIE(0)); | ||
455 | /* | ||
456 | * let SPDIF device re-lock with SPDIF signal, | ||
457 | * start with some silence | ||
458 | */ | ||
459 | card->silent = snd_ps3_delay_to_bytes(substream, | ||
460 | card->start_delay) / | ||
461 | (PS3_AUDIO_FIFO_STAGE_SIZE * 4); /* every 4 times */ | ||
462 | } | ||
463 | |||
464 | /* restart ring buffer pointer */ | ||
465 | spin_lock_irqsave(&card->dma_lock, irqsave); | ||
466 | { | ||
467 | card->dma_buffer_size = runtime->dma_bytes; | ||
468 | |||
469 | card->dma_last_transfer_vaddr[SND_PS3_CH_L] = | ||
470 | card->dma_next_transfer_vaddr[SND_PS3_CH_L] = | ||
471 | card->dma_start_vaddr[SND_PS3_CH_L] = | ||
472 | runtime->dma_area; | ||
473 | card->dma_start_bus_addr[SND_PS3_CH_L] = runtime->dma_addr; | ||
474 | |||
475 | card->dma_last_transfer_vaddr[SND_PS3_CH_R] = | ||
476 | card->dma_next_transfer_vaddr[SND_PS3_CH_R] = | ||
477 | card->dma_start_vaddr[SND_PS3_CH_R] = | ||
478 | runtime->dma_area + (runtime->dma_bytes / 2); | ||
479 | card->dma_start_bus_addr[SND_PS3_CH_R] = | ||
480 | runtime->dma_addr + (runtime->dma_bytes / 2); | ||
481 | |||
482 | pr_debug("%s: vaddr=%p bus=%#lx\n", __func__, | ||
483 | card->dma_start_vaddr[SND_PS3_CH_L], | ||
484 | card->dma_start_bus_addr[SND_PS3_CH_L]); | ||
485 | |||
486 | } | ||
487 | spin_unlock_irqrestore(&card->dma_lock, irqsave); | ||
488 | |||
489 | /* ensure the hardware sees the change */ | ||
490 | mb(); | ||
491 | |||
492 | return 0; | ||
493 | }; | ||
494 | |||
495 | static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, | ||
496 | int cmd) | ||
497 | { | ||
498 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | ||
499 | int ret = 0; | ||
500 | |||
501 | switch (cmd) { | ||
502 | case SNDRV_PCM_TRIGGER_START: | ||
503 | /* clear outstanding interrupts */ | ||
504 | update_reg(PS3_AUDIO_AX_IS, 0); | ||
505 | |||
506 | spin_lock(&card->dma_lock); | ||
507 | { | ||
508 | card->running = 1; | ||
509 | } | ||
510 | spin_unlock(&card->dma_lock); | ||
511 | |||
512 | snd_ps3_program_dma(card, | ||
513 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
514 | snd_ps3_kick_dma(card); | ||
515 | while (read_reg(PS3_AUDIO_KICK(7)) & | ||
516 | PS3_AUDIO_KICK_STATUS_MASK) { | ||
517 | udelay(1); | ||
518 | } | ||
519 | snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); | ||
520 | snd_ps3_kick_dma(card); | ||
521 | break; | ||
522 | |||
523 | case SNDRV_PCM_TRIGGER_STOP: | ||
524 | spin_lock(&card->dma_lock); | ||
525 | { | ||
526 | card->running = 0; | ||
527 | } | ||
528 | spin_unlock(&card->dma_lock); | ||
529 | snd_ps3_wait_for_dma_stop(card); | ||
530 | break; | ||
531 | default: | ||
532 | break; | ||
533 | |||
534 | } | ||
535 | |||
536 | return ret; | ||
537 | }; | ||
538 | |||
539 | /* | ||
540 | * report current pointer | ||
541 | */ | ||
542 | static snd_pcm_uframes_t snd_ps3_pcm_pointer( | ||
543 | struct snd_pcm_substream *substream) | ||
544 | { | ||
545 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | ||
546 | size_t bytes; | ||
547 | snd_pcm_uframes_t ret; | ||
548 | |||
549 | spin_lock(&card->dma_lock); | ||
550 | { | ||
551 | bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] - | ||
552 | card->dma_start_vaddr[SND_PS3_CH_L]); | ||
553 | } | ||
554 | spin_unlock(&card->dma_lock); | ||
555 | |||
556 | ret = bytes_to_frames(substream->runtime, bytes * 2); | ||
557 | |||
558 | return ret; | ||
559 | }; | ||
560 | |||
561 | static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) | ||
562 | { | ||
563 | int ret; | ||
564 | ret = snd_pcm_lib_free_pages(substream); | ||
565 | return ret; | ||
566 | }; | ||
567 | |||
568 | static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) | ||
569 | { | ||
570 | /* mute on */ | ||
571 | snd_ps3_mute(1); | ||
572 | return 0; | ||
573 | }; | ||
574 | |||
575 | static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) | ||
576 | { | ||
577 | /* | ||
578 | * avsetting driver seems to never change the followings | ||
579 | * so, init them here once | ||
580 | */ | ||
581 | |||
582 | /* no dma interrupt needed */ | ||
583 | write_reg(PS3_AUDIO_INTR_EN_0, 0); | ||
584 | |||
585 | /* use every 4 buffer empty interrupt */ | ||
586 | update_mask_reg(PS3_AUDIO_AX_IC, | ||
587 | PS3_AUDIO_AX_IC_AASOIMD_MASK, | ||
588 | PS3_AUDIO_AX_IC_AASOIMD_EVERY4); | ||
589 | |||
590 | /* enable 3wire clocks */ | ||
591 | update_mask_reg(PS3_AUDIO_AO_3WMCTRL, | ||
592 | ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | | ||
593 | PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), | ||
594 | 0); | ||
595 | update_reg(PS3_AUDIO_AO_3WMCTRL, | ||
596 | PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); | ||
597 | } | ||
598 | |||
599 | /* | ||
600 | * av setting | ||
601 | * NOTE: calling this function may generate audio interrupt. | ||
602 | */ | ||
603 | static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) | ||
604 | { | ||
605 | int ret, retries, i; | ||
606 | pr_debug("%s: start\n", __func__); | ||
607 | |||
608 | ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, | ||
609 | card->avs.avs_audio_rate, | ||
610 | card->avs.avs_audio_width, | ||
611 | card->avs.avs_audio_format, | ||
612 | card->avs.avs_audio_source); | ||
613 | /* | ||
614 | * Reset the following unwanted settings: | ||
615 | */ | ||
616 | |||
617 | /* disable all 3wire buffers */ | ||
618 | update_mask_reg(PS3_AUDIO_AO_3WMCTRL, | ||
619 | ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | | ||
620 | PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | | ||
621 | PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | | ||
622 | PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), | ||
623 | 0); | ||
624 | wmb(); /* ensure the hardware sees the change */ | ||
625 | /* wait for actually stopped */ | ||
626 | retries = 1000; | ||
627 | while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & | ||
628 | (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | | ||
629 | PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | | ||
630 | PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | | ||
631 | PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && | ||
632 | --retries) { | ||
633 | udelay(1); | ||
634 | } | ||
635 | |||
636 | /* reset buffer pointer */ | ||
637 | for (i = 0; i < 4; i++) { | ||
638 | update_reg(PS3_AUDIO_AO_3WCTRL(i), | ||
639 | PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); | ||
640 | udelay(10); | ||
641 | } | ||
642 | wmb(); /* ensure the hardware actually start resetting */ | ||
643 | |||
644 | /* enable 3wire#0 buffer */ | ||
645 | update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); | ||
646 | |||
647 | |||
648 | /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ | ||
649 | update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), | ||
650 | ~PS3_AUDIO_AO_3WCTRL_ASODF, | ||
651 | PS3_AUDIO_AO_3WCTRL_ASODF_LSB); | ||
652 | update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), | ||
653 | ~PS3_AUDIO_AO_SPDCTRL_SPODF, | ||
654 | PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); | ||
655 | /* ensure all the setting above is written back to register */ | ||
656 | wmb(); | ||
657 | /* avsetting driver altered AX_IE, caller must reset it if you want */ | ||
658 | pr_debug("%s: end\n", __func__); | ||
659 | return ret; | ||
660 | } | ||
661 | |||
662 | static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) | ||
663 | { | ||
664 | int ret; | ||
665 | pr_debug("%s: start\n", __func__); | ||
666 | card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; | ||
667 | card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; | ||
668 | card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; | ||
669 | card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; | ||
670 | card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; | ||
671 | |||
672 | ret = snd_ps3_change_avsetting(card); | ||
673 | |||
674 | snd_ps3_audio_fixup(card); | ||
675 | |||
676 | /* to start to generate SPDIF signal, fill data */ | ||
677 | snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
678 | snd_ps3_kick_dma(card); | ||
679 | pr_debug("%s: end\n", __func__); | ||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * set sampling rate according to the substream | ||
685 | */ | ||
686 | static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) | ||
687 | { | ||
688 | struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); | ||
689 | struct snd_ps3_avsetting_info avs; | ||
690 | |||
691 | avs = card->avs; | ||
692 | |||
693 | pr_debug("%s: called freq=%d width=%d\n", __func__, | ||
694 | substream->runtime->rate, | ||
695 | snd_pcm_format_width(substream->runtime->format)); | ||
696 | |||
697 | pr_debug("%s: before freq=%d width=%d\n", __func__, | ||
698 | card->avs.avs_audio_rate, card->avs.avs_audio_width); | ||
699 | |||
700 | /* sample rate */ | ||
701 | switch (substream->runtime->rate) { | ||
702 | case 44100: | ||
703 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; | ||
704 | break; | ||
705 | case 48000: | ||
706 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; | ||
707 | break; | ||
708 | case 88200: | ||
709 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; | ||
710 | break; | ||
711 | case 96000: | ||
712 | avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; | ||
713 | break; | ||
714 | default: | ||
715 | pr_info("%s: invalid rate %d\n", __func__, | ||
716 | substream->runtime->rate); | ||
717 | return 1; | ||
718 | } | ||
719 | |||
720 | /* width */ | ||
721 | switch (snd_pcm_format_width(substream->runtime->format)) { | ||
722 | case 16: | ||
723 | avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; | ||
724 | break; | ||
725 | case 24: | ||
726 | avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; | ||
727 | break; | ||
728 | default: | ||
729 | pr_info("%s: invalid width %d\n", __func__, | ||
730 | snd_pcm_format_width(substream->runtime->format)); | ||
731 | return 1; | ||
732 | } | ||
733 | |||
734 | if ((card->avs.avs_audio_width != avs.avs_audio_width) || | ||
735 | (card->avs.avs_audio_rate != avs.avs_audio_rate)) { | ||
736 | card->avs = avs; | ||
737 | snd_ps3_change_avsetting(card); | ||
738 | |||
739 | pr_debug("%s: after freq=%d width=%d\n", __func__, | ||
740 | card->avs.avs_audio_rate, card->avs.avs_audio_width); | ||
741 | |||
742 | return 0; | ||
743 | } else | ||
744 | return 1; | ||
745 | } | ||
746 | |||
747 | |||
748 | |||
749 | static int snd_ps3_map_mmio(void) | ||
750 | { | ||
751 | the_card.mapped_mmio_vaddr = | ||
752 | ioremap(the_card.ps3_dev->m_region->bus_addr, | ||
753 | the_card.ps3_dev->m_region->len); | ||
754 | |||
755 | if (!the_card.mapped_mmio_vaddr) { | ||
756 | pr_info("%s: ioremap 0 failed p=%#lx l=%#lx \n", | ||
757 | __func__, the_card.ps3_dev->m_region->lpar_addr, | ||
758 | the_card.ps3_dev->m_region->len); | ||
759 | return -ENXIO; | ||
760 | } | ||
761 | |||
762 | return 0; | ||
763 | }; | ||
764 | |||
765 | static void snd_ps3_unmap_mmio(void) | ||
766 | { | ||
767 | iounmap(the_card.mapped_mmio_vaddr); | ||
768 | the_card.mapped_mmio_vaddr = NULL; | ||
769 | } | ||
770 | |||
771 | static int snd_ps3_allocate_irq(void) | ||
772 | { | ||
773 | int ret; | ||
774 | u64 lpar_addr, lpar_size; | ||
775 | u64 __iomem *mapped; | ||
776 | |||
777 | /* FIXME: move this to device_init (H/W probe) */ | ||
778 | |||
779 | /* get irq outlet */ | ||
780 | ret = lv1_gpu_device_map(1, &lpar_addr, &lpar_size); | ||
781 | if (ret) { | ||
782 | pr_info("%s: device map 1 failed %d\n", __func__, | ||
783 | ret); | ||
784 | return -ENXIO; | ||
785 | } | ||
786 | |||
787 | mapped = ioremap(lpar_addr, lpar_size); | ||
788 | if (!mapped) { | ||
789 | pr_info("%s: ioremap 1 failed \n", __func__); | ||
790 | return -ENXIO; | ||
791 | } | ||
792 | |||
793 | the_card.audio_irq_outlet = in_be64(mapped); | ||
794 | |||
795 | iounmap(mapped); | ||
796 | ret = lv1_gpu_device_unmap(1); | ||
797 | if (ret) | ||
798 | pr_info("%s: unmap 1 failed\n", __func__); | ||
799 | |||
800 | /* irq */ | ||
801 | ret = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, | ||
802 | the_card.audio_irq_outlet, | ||
803 | &the_card.irq_no); | ||
804 | if (ret) { | ||
805 | pr_info("%s:ps3_alloc_irq failed (%d)\n", __func__, ret); | ||
806 | return ret; | ||
807 | } | ||
808 | |||
809 | ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED, | ||
810 | SND_PS3_DRIVER_NAME, &the_card); | ||
811 | if (ret) { | ||
812 | pr_info("%s: request_irq failed (%d)\n", __func__, ret); | ||
813 | goto cleanup_irq; | ||
814 | } | ||
815 | |||
816 | return 0; | ||
817 | |||
818 | cleanup_irq: | ||
819 | ps3_irq_plug_destroy(the_card.irq_no); | ||
820 | return ret; | ||
821 | }; | ||
822 | |||
823 | static void snd_ps3_free_irq(void) | ||
824 | { | ||
825 | free_irq(the_card.irq_no, &the_card); | ||
826 | ps3_irq_plug_destroy(the_card.irq_no); | ||
827 | } | ||
828 | |||
829 | static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) | ||
830 | { | ||
831 | uint64_t val; | ||
832 | int ret; | ||
833 | |||
834 | val = (ioaddr_start & (0x0fUL << 32)) >> (32 - 20) | | ||
835 | (0x03UL << 24) | | ||
836 | (0x0fUL << 12) | | ||
837 | (PS3_AUDIO_IOID); | ||
838 | |||
839 | ret = lv1_gpu_attribute(0x100, 0x007, val, 0, 0); | ||
840 | if (ret) | ||
841 | pr_info("%s: gpu_attribute failed %d\n", __func__, | ||
842 | ret); | ||
843 | } | ||
844 | |||
845 | static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) | ||
846 | { | ||
847 | int ret; | ||
848 | u64 lpar_addr, lpar_size; | ||
849 | |||
850 | BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); | ||
851 | BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND); | ||
852 | |||
853 | the_card.ps3_dev = dev; | ||
854 | |||
855 | ret = ps3_open_hv_device(dev); | ||
856 | |||
857 | if (ret) | ||
858 | return -ENXIO; | ||
859 | |||
860 | /* setup MMIO */ | ||
861 | ret = lv1_gpu_device_map(2, &lpar_addr, &lpar_size); | ||
862 | if (ret) { | ||
863 | pr_info("%s: device map 2 failed %d\n", __func__, ret); | ||
864 | goto clean_open; | ||
865 | } | ||
866 | ps3_mmio_region_init(dev, dev->m_region, lpar_addr, lpar_size, | ||
867 | PAGE_SHIFT); | ||
868 | |||
869 | ret = snd_ps3_map_mmio(); | ||
870 | if (ret) | ||
871 | goto clean_dev_map; | ||
872 | |||
873 | /* setup DMA area */ | ||
874 | ps3_dma_region_init(dev, dev->d_region, | ||
875 | PAGE_SHIFT, /* use system page size */ | ||
876 | 0, /* dma type; not used */ | ||
877 | NULL, | ||
878 | _ALIGN_UP(SND_PS3_DMA_REGION_SIZE, PAGE_SIZE)); | ||
879 | dev->d_region->ioid = PS3_AUDIO_IOID; | ||
880 | |||
881 | ret = ps3_dma_region_create(dev->d_region); | ||
882 | if (ret) { | ||
883 | pr_info("%s: region_create\n", __func__); | ||
884 | goto clean_mmio; | ||
885 | } | ||
886 | |||
887 | snd_ps3_audio_set_base_addr(dev->d_region->bus_addr); | ||
888 | |||
889 | /* CONFIG_SND_PS3_DEFAULT_START_DELAY */ | ||
890 | the_card.start_delay = snd_ps3_start_delay; | ||
891 | |||
892 | /* irq */ | ||
893 | if (snd_ps3_allocate_irq()) { | ||
894 | ret = -ENXIO; | ||
895 | goto clean_dma_region; | ||
896 | } | ||
897 | |||
898 | /* create card instance */ | ||
899 | the_card.card = snd_card_new(index, id, THIS_MODULE, 0); | ||
900 | if (!the_card.card) { | ||
901 | ret = -ENXIO; | ||
902 | goto clean_irq; | ||
903 | } | ||
904 | |||
905 | strcpy(the_card.card->driver, "PS3"); | ||
906 | strcpy(the_card.card->shortname, "PS3"); | ||
907 | strcpy(the_card.card->longname, "PS3 sound"); | ||
908 | /* create PCM devices instance */ | ||
909 | /* NOTE:this driver works assuming pcm:substream = 1:1 */ | ||
910 | ret = snd_pcm_new(the_card.card, | ||
911 | "SPDIF", | ||
912 | 0, /* instance index, will be stored pcm.device*/ | ||
913 | 1, /* output substream */ | ||
914 | 0, /* input substream */ | ||
915 | &(the_card.pcm)); | ||
916 | if (ret) | ||
917 | goto clean_card; | ||
918 | |||
919 | the_card.pcm->private_data = &the_card; | ||
920 | strcpy(the_card.pcm->name, "SPDIF"); | ||
921 | |||
922 | /* set pcm ops */ | ||
923 | snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
924 | &snd_ps3_pcm_spdif_ops); | ||
925 | |||
926 | the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED; | ||
927 | /* pre-alloc PCM DMA buffer*/ | ||
928 | ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm, | ||
929 | SNDRV_DMA_TYPE_DEV, | ||
930 | &dev->core, | ||
931 | SND_PS3_PCM_PREALLOC_SIZE, | ||
932 | SND_PS3_PCM_PREALLOC_SIZE); | ||
933 | if (ret < 0) { | ||
934 | pr_info("%s: prealloc failed\n", __func__); | ||
935 | goto clean_card; | ||
936 | } | ||
937 | |||
938 | /* | ||
939 | * allocate null buffer | ||
940 | * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2 | ||
941 | * PAGE_SIZE is enogh | ||
942 | */ | ||
943 | if (!(the_card.null_buffer_start_vaddr = | ||
944 | dma_alloc_coherent(&the_card.ps3_dev->core, | ||
945 | PAGE_SIZE, | ||
946 | &the_card.null_buffer_start_dma_addr, | ||
947 | GFP_KERNEL))) { | ||
948 | pr_info("%s: nullbuffer alloc failed\n", __func__); | ||
949 | goto clean_preallocate; | ||
950 | } | ||
951 | pr_debug("%s: null vaddr=%p dma=%#lx\n", __func__, | ||
952 | the_card.null_buffer_start_vaddr, | ||
953 | the_card.null_buffer_start_dma_addr); | ||
954 | /* set default sample rate/word width */ | ||
955 | snd_ps3_init_avsetting(&the_card); | ||
956 | |||
957 | /* register the card */ | ||
958 | ret = snd_card_register(the_card.card); | ||
959 | if (ret < 0) | ||
960 | goto clean_dma_map; | ||
961 | |||
962 | pr_info("%s started. start_delay=%dms\n", | ||
963 | the_card.card->longname, the_card.start_delay); | ||
964 | return 0; | ||
965 | |||
966 | clean_dma_map: | ||
967 | dma_free_coherent(&the_card.ps3_dev->core, | ||
968 | PAGE_SIZE, | ||
969 | the_card.null_buffer_start_vaddr, | ||
970 | the_card.null_buffer_start_dma_addr); | ||
971 | clean_preallocate: | ||
972 | snd_pcm_lib_preallocate_free_for_all(the_card.pcm); | ||
973 | clean_card: | ||
974 | snd_card_free(the_card.card); | ||
975 | clean_irq: | ||
976 | snd_ps3_free_irq(); | ||
977 | clean_dma_region: | ||
978 | ps3_dma_region_free(dev->d_region); | ||
979 | clean_mmio: | ||
980 | snd_ps3_unmap_mmio(); | ||
981 | clean_dev_map: | ||
982 | lv1_gpu_device_unmap(2); | ||
983 | clean_open: | ||
984 | ps3_close_hv_device(dev); | ||
985 | /* | ||
986 | * there is no destructor function to pcm. | ||
987 | * midlayer automatically releases if the card removed | ||
988 | */ | ||
989 | return ret; | ||
990 | }; /* snd_ps3_probe */ | ||
991 | |||
992 | /* called when module removal */ | ||
993 | static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev) | ||
994 | { | ||
995 | int ret; | ||
996 | pr_info("%s:start id=%d\n", __func__, dev->match_id); | ||
997 | if (dev->match_id != PS3_MATCH_ID_SOUND) | ||
998 | return -ENXIO; | ||
999 | |||
1000 | /* | ||
1001 | * ctl and preallocate buffer will be freed in | ||
1002 | * snd_card_free | ||
1003 | */ | ||
1004 | ret = snd_card_free(the_card.card); | ||
1005 | if (ret) | ||
1006 | pr_info("%s: ctl freecard=%d\n", __func__, ret); | ||
1007 | |||
1008 | dma_free_coherent(&dev->core, | ||
1009 | PAGE_SIZE, | ||
1010 | the_card.null_buffer_start_vaddr, | ||
1011 | the_card.null_buffer_start_dma_addr); | ||
1012 | |||
1013 | ps3_dma_region_free(dev->d_region); | ||
1014 | |||
1015 | snd_ps3_free_irq(); | ||
1016 | snd_ps3_unmap_mmio(); | ||
1017 | |||
1018 | lv1_gpu_device_unmap(2); | ||
1019 | ps3_close_hv_device(dev); | ||
1020 | pr_info("%s:end id=%d\n", __func__, dev->match_id); | ||
1021 | return 0; | ||
1022 | } /* snd_ps3_remove */ | ||
1023 | |||
1024 | static struct ps3_system_bus_driver snd_ps3_bus_driver_info = { | ||
1025 | .match_id = PS3_MATCH_ID_SOUND, | ||
1026 | .probe = snd_ps3_driver_probe, | ||
1027 | .remove = snd_ps3_driver_remove, | ||
1028 | .shutdown = snd_ps3_driver_remove, | ||
1029 | .core = { | ||
1030 | .name = SND_PS3_DRIVER_NAME, | ||
1031 | .owner = THIS_MODULE, | ||
1032 | }, | ||
1033 | }; | ||
1034 | |||
1035 | |||
1036 | /* | ||
1037 | * Interrupt handler | ||
1038 | */ | ||
1039 | static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) | ||
1040 | { | ||
1041 | |||
1042 | uint32_t port_intr; | ||
1043 | int underflow_occured = 0; | ||
1044 | struct snd_ps3_card_info *card = dev_id; | ||
1045 | |||
1046 | if (!card->running) { | ||
1047 | update_reg(PS3_AUDIO_AX_IS, 0); | ||
1048 | update_reg(PS3_AUDIO_INTR_0, 0); | ||
1049 | return IRQ_HANDLED; | ||
1050 | } | ||
1051 | |||
1052 | port_intr = read_reg(PS3_AUDIO_AX_IS); | ||
1053 | /* | ||
1054 | *serial buffer empty detected (every 4 times), | ||
1055 | *program next dma and kick it | ||
1056 | */ | ||
1057 | if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { | ||
1058 | write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); | ||
1059 | if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { | ||
1060 | write_reg(PS3_AUDIO_AX_IS, port_intr); | ||
1061 | underflow_occured = 1; | ||
1062 | } | ||
1063 | if (card->silent) { | ||
1064 | /* we are still in silent time */ | ||
1065 | snd_ps3_program_dma(card, | ||
1066 | (underflow_occured) ? | ||
1067 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : | ||
1068 | SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); | ||
1069 | snd_ps3_kick_dma(card); | ||
1070 | card->silent --; | ||
1071 | } else { | ||
1072 | snd_ps3_program_dma(card, | ||
1073 | (underflow_occured) ? | ||
1074 | SND_PS3_DMA_FILLTYPE_FIRSTFILL : | ||
1075 | SND_PS3_DMA_FILLTYPE_RUNNING); | ||
1076 | snd_ps3_kick_dma(card); | ||
1077 | snd_pcm_period_elapsed(card->substream); | ||
1078 | } | ||
1079 | } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { | ||
1080 | write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); | ||
1081 | /* | ||
1082 | * serial out underflow, but buffer empty not detected. | ||
1083 | * in this case, fill fifo with 0 to recover. After | ||
1084 | * filling dummy data, serial automatically start to | ||
1085 | * consume them and then will generate normal buffer | ||
1086 | * empty interrupts. | ||
1087 | * If both buffer underflow and buffer empty are occured, | ||
1088 | * it is better to do nomal data transfer than empty one | ||
1089 | */ | ||
1090 | snd_ps3_program_dma(card, | ||
1091 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
1092 | snd_ps3_kick_dma(card); | ||
1093 | snd_ps3_program_dma(card, | ||
1094 | SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); | ||
1095 | snd_ps3_kick_dma(card); | ||
1096 | } | ||
1097 | /* clear interrupt cause */ | ||
1098 | return IRQ_HANDLED; | ||
1099 | }; | ||
1100 | |||
1101 | /* | ||
1102 | * module/subsystem initialize/terminate | ||
1103 | */ | ||
1104 | static int __init snd_ps3_init(void) | ||
1105 | { | ||
1106 | int ret; | ||
1107 | |||
1108 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
1109 | return -ENXIO; | ||
1110 | |||
1111 | memset(&the_card, 0, sizeof(the_card)); | ||
1112 | spin_lock_init(&the_card.dma_lock); | ||
1113 | |||
1114 | /* register systembus DRIVER, this calls our probe() func */ | ||
1115 | ret = ps3_system_bus_driver_register(&snd_ps3_bus_driver_info); | ||
1116 | |||
1117 | return ret; | ||
1118 | } | ||
1119 | |||
1120 | static void __exit snd_ps3_exit(void) | ||
1121 | { | ||
1122 | ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info); | ||
1123 | } | ||
1124 | |||
1125 | MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND); | ||