2 * Driver for audio on multifunction CS5535 companion device
3 * Copyright (C) Jaya Kumar
5 * Based on Jaroslav Kysela and Takashi Iwai's examples.
6 * This work was sponsored by CIS(M) Sdn Bhd.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * todo: add be fmt support, spdif, pm
25 #include <linux/init.h>
26 #include <linux/slab.h>
27 #include <linux/pci.h>
28 #include <sound/core.h>
29 #include <sound/control.h>
30 #include <sound/initval.h>
31 #include <sound/asoundef.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/ac97_codec.h>
35 #include "cs5535audio.h"
37 static struct snd_pcm_hardware snd_cs5535audio_playback
=
41 SNDRV_PCM_INFO_INTERLEAVED
|
42 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
43 SNDRV_PCM_INFO_MMAP_VALID
|
44 SNDRV_PCM_INFO_PAUSE
|
48 SNDRV_PCM_FMTBIT_S16_LE
51 SNDRV_PCM_RATE_CONTINUOUS
|
52 SNDRV_PCM_RATE_8000_48000
58 .buffer_bytes_max
= (128*1024),
59 .period_bytes_min
= 64,
60 .period_bytes_max
= (64*1024 - 16),
62 .periods_max
= CS5535AUDIO_MAX_DESCRIPTORS
,
66 static struct snd_pcm_hardware snd_cs5535audio_capture
=
70 SNDRV_PCM_INFO_INTERLEAVED
|
71 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
72 SNDRV_PCM_INFO_MMAP_VALID
75 SNDRV_PCM_FMTBIT_S16_LE
78 SNDRV_PCM_RATE_CONTINUOUS
|
79 SNDRV_PCM_RATE_8000_48000
85 .buffer_bytes_max
= (128*1024),
86 .period_bytes_min
= 64,
87 .period_bytes_max
= (64*1024 - 16),
89 .periods_max
= CS5535AUDIO_MAX_DESCRIPTORS
,
93 static int snd_cs5535audio_playback_open(struct snd_pcm_substream
*substream
)
96 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
97 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
99 runtime
->hw
= snd_cs5535audio_playback
;
100 runtime
->hw
.rates
= cs5535au
->ac97
->rates
[AC97_RATES_FRONT_DAC
];
101 snd_pcm_limit_hw_rates(runtime
);
102 cs5535au
->playback_substream
= substream
;
103 runtime
->private_data
= &(cs5535au
->dmas
[CS5535AUDIO_DMA_PLAYBACK
]);
104 if ((err
= snd_pcm_hw_constraint_integer(runtime
,
105 SNDRV_PCM_HW_PARAM_PERIODS
)) < 0)
111 static int snd_cs5535audio_playback_close(struct snd_pcm_substream
*substream
)
116 #define CS5535AUDIO_DESC_LIST_SIZE \
117 PAGE_ALIGN(CS5535AUDIO_MAX_DESCRIPTORS * sizeof(struct cs5535audio_dma_desc))
119 static int cs5535audio_build_dma_packets(struct cs5535audio
*cs5535au
,
120 struct cs5535audio_dma
*dma
,
121 struct snd_pcm_substream
*substream
,
122 unsigned int periods
,
123 unsigned int period_bytes
)
126 u32 addr
, desc_addr
, jmpprd_addr
;
127 struct cs5535audio_dma_desc
*lastdesc
;
129 if (periods
> CS5535AUDIO_MAX_DESCRIPTORS
)
132 if (dma
->desc_buf
.area
== NULL
) {
133 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
134 snd_dma_pci_data(cs5535au
->pci
),
135 CS5535AUDIO_DESC_LIST_SIZE
+1,
138 dma
->period_bytes
= dma
->periods
= 0;
141 if (dma
->periods
== periods
&& dma
->period_bytes
== period_bytes
)
144 /* the u32 cast is okay because in snd*create we successfully told
145 pci alloc that we're only 32 bit capable so the uppper will be 0 */
146 addr
= (u32
) substream
->runtime
->dma_addr
;
147 desc_addr
= (u32
) dma
->desc_buf
.addr
;
148 for (i
= 0; i
< periods
; i
++) {
149 struct cs5535audio_dma_desc
*desc
=
150 &((struct cs5535audio_dma_desc
*) dma
->desc_buf
.area
)[i
];
151 desc
->addr
= cpu_to_le32(addr
);
152 desc
->size
= cpu_to_le32(period_bytes
);
153 desc
->ctlreserved
= cpu_to_le32(PRD_EOP
);
154 desc_addr
+= sizeof(struct cs5535audio_dma_desc
);
155 addr
+= period_bytes
;
157 /* we reserved one dummy descriptor at the end to do the PRD jump */
158 lastdesc
= &((struct cs5535audio_dma_desc
*) dma
->desc_buf
.area
)[periods
];
159 lastdesc
->addr
= cpu_to_le32((u32
) dma
->desc_buf
.addr
);
161 lastdesc
->ctlreserved
= cpu_to_le32(PRD_JMP
);
162 jmpprd_addr
= cpu_to_le32(lastdesc
->addr
+
163 (sizeof(struct cs5535audio_dma_desc
)*periods
));
165 dma
->substream
= substream
;
166 dma
->period_bytes
= period_bytes
;
167 dma
->periods
= periods
;
168 spin_lock_irq(&cs5535au
->reg_lock
);
169 dma
->ops
->disable_dma(cs5535au
);
170 dma
->ops
->setup_prd(cs5535au
, jmpprd_addr
);
171 spin_unlock_irq(&cs5535au
->reg_lock
);
175 static void cs5535audio_playback_enable_dma(struct cs5535audio
*cs5535au
)
177 cs_writeb(cs5535au
, ACC_BM0_CMD
, BM_CTL_EN
);
180 static void cs5535audio_playback_disable_dma(struct cs5535audio
*cs5535au
)
182 cs_writeb(cs5535au
, ACC_BM0_CMD
, 0);
185 static void cs5535audio_playback_pause_dma(struct cs5535audio
*cs5535au
)
187 cs_writeb(cs5535au
, ACC_BM0_CMD
, BM_CTL_PAUSE
);
190 static void cs5535audio_playback_setup_prd(struct cs5535audio
*cs5535au
,
193 cs_writel(cs5535au
, ACC_BM0_PRD
, prd_addr
);
196 static u32
cs5535audio_playback_read_prd(struct cs5535audio
*cs5535au
)
198 return cs_readl(cs5535au
, ACC_BM0_PRD
);
201 static u32
cs5535audio_playback_read_dma_pntr(struct cs5535audio
*cs5535au
)
203 return cs_readl(cs5535au
, ACC_BM0_PNTR
);
206 static void cs5535audio_capture_enable_dma(struct cs5535audio
*cs5535au
)
208 cs_writeb(cs5535au
, ACC_BM1_CMD
, BM_CTL_EN
);
211 static void cs5535audio_capture_disable_dma(struct cs5535audio
*cs5535au
)
213 cs_writeb(cs5535au
, ACC_BM1_CMD
, 0);
216 static void cs5535audio_capture_pause_dma(struct cs5535audio
*cs5535au
)
218 cs_writeb(cs5535au
, ACC_BM1_CMD
, BM_CTL_PAUSE
);
221 static void cs5535audio_capture_setup_prd(struct cs5535audio
*cs5535au
,
224 cs_writel(cs5535au
, ACC_BM1_PRD
, prd_addr
);
227 static u32
cs5535audio_capture_read_prd(struct cs5535audio
*cs5535au
)
229 return cs_readl(cs5535au
, ACC_BM1_PRD
);
232 static u32
cs5535audio_capture_read_dma_pntr(struct cs5535audio
*cs5535au
)
234 return cs_readl(cs5535au
, ACC_BM1_PNTR
);
237 static void cs5535audio_clear_dma_packets(struct cs5535audio
*cs5535au
,
238 struct cs5535audio_dma
*dma
,
239 struct snd_pcm_substream
*substream
)
241 snd_dma_free_pages(&dma
->desc_buf
);
242 dma
->desc_buf
.area
= NULL
;
243 dma
->substream
= NULL
;
246 static int snd_cs5535audio_hw_params(struct snd_pcm_substream
*substream
,
247 struct snd_pcm_hw_params
*hw_params
)
249 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
250 struct cs5535audio_dma
*dma
= substream
->runtime
->private_data
;
253 err
= snd_pcm_lib_malloc_pages(substream
,
254 params_buffer_bytes(hw_params
));
257 dma
->buf_addr
= substream
->runtime
->dma_addr
;
258 dma
->buf_bytes
= params_buffer_bytes(hw_params
);
260 err
= cs5535audio_build_dma_packets(cs5535au
, dma
, substream
,
261 params_periods(hw_params
),
262 params_period_bytes(hw_params
));
264 dma
->pcm_open_flag
= 1;
269 static int snd_cs5535audio_hw_free(struct snd_pcm_substream
*substream
)
271 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
272 struct cs5535audio_dma
*dma
= substream
->runtime
->private_data
;
274 if (dma
->pcm_open_flag
) {
275 if (substream
== cs5535au
->playback_substream
)
276 snd_ac97_update_power(cs5535au
->ac97
,
277 AC97_PCM_FRONT_DAC_RATE
, 0);
279 snd_ac97_update_power(cs5535au
->ac97
,
280 AC97_PCM_LR_ADC_RATE
, 0);
281 dma
->pcm_open_flag
= 0;
283 cs5535audio_clear_dma_packets(cs5535au
, dma
, substream
);
284 return snd_pcm_lib_free_pages(substream
);
287 static int snd_cs5535audio_playback_prepare(struct snd_pcm_substream
*substream
)
289 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
290 return snd_ac97_set_rate(cs5535au
->ac97
, AC97_PCM_FRONT_DAC_RATE
,
291 substream
->runtime
->rate
);
294 static int snd_cs5535audio_trigger(struct snd_pcm_substream
*substream
, int cmd
)
296 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
297 struct cs5535audio_dma
*dma
= substream
->runtime
->private_data
;
300 spin_lock(&cs5535au
->reg_lock
);
302 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
303 dma
->ops
->pause_dma(cs5535au
);
305 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
306 dma
->ops
->enable_dma(cs5535au
);
308 case SNDRV_PCM_TRIGGER_START
:
309 dma
->ops
->enable_dma(cs5535au
);
311 case SNDRV_PCM_TRIGGER_RESUME
:
312 dma
->ops
->enable_dma(cs5535au
);
314 case SNDRV_PCM_TRIGGER_STOP
:
315 dma
->ops
->disable_dma(cs5535au
);
317 case SNDRV_PCM_TRIGGER_SUSPEND
:
318 dma
->ops
->disable_dma(cs5535au
);
321 snd_printk(KERN_ERR
"unhandled trigger\n");
325 spin_unlock(&cs5535au
->reg_lock
);
329 static snd_pcm_uframes_t
snd_cs5535audio_pcm_pointer(struct snd_pcm_substream
332 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
334 struct cs5535audio_dma
*dma
;
336 dma
= substream
->runtime
->private_data
;
337 curdma
= dma
->ops
->read_dma_pntr(cs5535au
);
338 if (curdma
< dma
->buf_addr
) {
339 snd_printk(KERN_ERR
"curdma=%x < %x bufaddr.\n",
340 curdma
, dma
->buf_addr
);
343 curdma
-= dma
->buf_addr
;
344 if (curdma
>= dma
->buf_bytes
) {
345 snd_printk(KERN_ERR
"diff=%x >= %x buf_bytes.\n",
346 curdma
, dma
->buf_bytes
);
349 return bytes_to_frames(substream
->runtime
, curdma
);
352 static int snd_cs5535audio_capture_open(struct snd_pcm_substream
*substream
)
355 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
356 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
358 runtime
->hw
= snd_cs5535audio_capture
;
359 runtime
->hw
.rates
= cs5535au
->ac97
->rates
[AC97_RATES_ADC
];
360 snd_pcm_limit_hw_rates(runtime
);
361 cs5535au
->capture_substream
= substream
;
362 runtime
->private_data
= &(cs5535au
->dmas
[CS5535AUDIO_DMA_CAPTURE
]);
363 if ((err
= snd_pcm_hw_constraint_integer(runtime
,
364 SNDRV_PCM_HW_PARAM_PERIODS
)) < 0)
366 olpc_capture_open(cs5535au
->ac97
);
370 static int snd_cs5535audio_capture_close(struct snd_pcm_substream
*substream
)
372 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
373 olpc_capture_close(cs5535au
->ac97
);
377 static int snd_cs5535audio_capture_prepare(struct snd_pcm_substream
*substream
)
379 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
380 return snd_ac97_set_rate(cs5535au
->ac97
, AC97_PCM_LR_ADC_RATE
,
381 substream
->runtime
->rate
);
384 static struct snd_pcm_ops snd_cs5535audio_playback_ops
= {
385 .open
= snd_cs5535audio_playback_open
,
386 .close
= snd_cs5535audio_playback_close
,
387 .ioctl
= snd_pcm_lib_ioctl
,
388 .hw_params
= snd_cs5535audio_hw_params
,
389 .hw_free
= snd_cs5535audio_hw_free
,
390 .prepare
= snd_cs5535audio_playback_prepare
,
391 .trigger
= snd_cs5535audio_trigger
,
392 .pointer
= snd_cs5535audio_pcm_pointer
,
395 static struct snd_pcm_ops snd_cs5535audio_capture_ops
= {
396 .open
= snd_cs5535audio_capture_open
,
397 .close
= snd_cs5535audio_capture_close
,
398 .ioctl
= snd_pcm_lib_ioctl
,
399 .hw_params
= snd_cs5535audio_hw_params
,
400 .hw_free
= snd_cs5535audio_hw_free
,
401 .prepare
= snd_cs5535audio_capture_prepare
,
402 .trigger
= snd_cs5535audio_trigger
,
403 .pointer
= snd_cs5535audio_pcm_pointer
,
406 static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops
= {
407 .type
= CS5535AUDIO_DMA_PLAYBACK
,
408 .enable_dma
= cs5535audio_playback_enable_dma
,
409 .disable_dma
= cs5535audio_playback_disable_dma
,
410 .setup_prd
= cs5535audio_playback_setup_prd
,
411 .read_prd
= cs5535audio_playback_read_prd
,
412 .pause_dma
= cs5535audio_playback_pause_dma
,
413 .read_dma_pntr
= cs5535audio_playback_read_dma_pntr
,
416 static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops
= {
417 .type
= CS5535AUDIO_DMA_CAPTURE
,
418 .enable_dma
= cs5535audio_capture_enable_dma
,
419 .disable_dma
= cs5535audio_capture_disable_dma
,
420 .setup_prd
= cs5535audio_capture_setup_prd
,
421 .read_prd
= cs5535audio_capture_read_prd
,
422 .pause_dma
= cs5535audio_capture_pause_dma
,
423 .read_dma_pntr
= cs5535audio_capture_read_dma_pntr
,
426 int __devinit
snd_cs5535audio_pcm(struct cs5535audio
*cs5535au
)
431 err
= snd_pcm_new(cs5535au
->card
, "CS5535 Audio", 0, 1, 1, &pcm
);
435 cs5535au
->dmas
[CS5535AUDIO_DMA_PLAYBACK
].ops
=
436 &snd_cs5535audio_playback_dma_ops
;
437 cs5535au
->dmas
[CS5535AUDIO_DMA_CAPTURE
].ops
=
438 &snd_cs5535audio_capture_dma_ops
;
439 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
,
440 &snd_cs5535audio_playback_ops
);
441 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
,
442 &snd_cs5535audio_capture_ops
);
444 pcm
->private_data
= cs5535au
;
446 strcpy(pcm
->name
, "CS5535 Audio");
448 snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_DEV
,
449 snd_dma_pci_data(cs5535au
->pci
),