Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cs5535audio_pcm.c
Go to the documentation of this file.
1 /*
2  * Driver for audio on multifunction CS5535 companion device
3  * Copyright (C) Jaya Kumar
4  *
5  * Based on Jaroslav Kysela and Takashi Iwai's examples.
6  * This work was sponsored by CIS(M) Sdn Bhd.
7  *
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.
12  *
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.
17  *
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
21  *
22  * todo: add be fmt support, spdif, pm
23  */
24 
25 #include <linux/init.h>
26 #include <linux/pci.h>
27 #include <sound/core.h>
28 #include <sound/control.h>
29 #include <sound/initval.h>
30 #include <sound/asoundef.h>
31 #include <sound/pcm.h>
32 #include <sound/pcm_params.h>
33 #include <sound/ac97_codec.h>
34 #include "cs5535audio.h"
35 
36 static struct snd_pcm_hardware snd_cs5535audio_playback =
37 {
38  .info = (
45  ),
46  .formats = (
48  ),
49  .rates = (
52  ),
53  .rate_min = 4000,
54  .rate_max = 48000,
55  .channels_min = 2,
56  .channels_max = 2,
57  .buffer_bytes_max = (128*1024),
58  .period_bytes_min = 64,
59  .period_bytes_max = (64*1024 - 16),
60  .periods_min = 1,
62  .fifo_size = 0,
63 };
64 
65 static struct snd_pcm_hardware snd_cs5535audio_capture =
66 {
67  .info = (
72  ),
73  .formats = (
75  ),
76  .rates = (
79  ),
80  .rate_min = 4000,
81  .rate_max = 48000,
82  .channels_min = 2,
83  .channels_max = 2,
84  .buffer_bytes_max = (128*1024),
85  .period_bytes_min = 64,
86  .period_bytes_max = (64*1024 - 16),
87  .periods_min = 1,
89  .fifo_size = 0,
90 };
91 
92 static int snd_cs5535audio_playback_open(struct snd_pcm_substream *substream)
93 {
94  int err;
95  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
96  struct snd_pcm_runtime *runtime = substream->runtime;
97 
98  runtime->hw = snd_cs5535audio_playback;
99  runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_FRONT_DAC];
100  snd_pcm_limit_hw_rates(runtime);
101  cs5535au->playback_substream = substream;
102  runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]);
103  if ((err = snd_pcm_hw_constraint_integer(runtime,
105  return err;
106 
107  return 0;
108 }
109 
110 static int snd_cs5535audio_playback_close(struct snd_pcm_substream *substream)
111 {
112  return 0;
113 }
114 
115 #define CS5535AUDIO_DESC_LIST_SIZE \
116  PAGE_ALIGN(CS5535AUDIO_MAX_DESCRIPTORS * sizeof(struct cs5535audio_dma_desc))
117 
118 static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
119  struct cs5535audio_dma *dma,
120  struct snd_pcm_substream *substream,
121  unsigned int periods,
122  unsigned int period_bytes)
123 {
124  unsigned int i;
125  u32 addr, desc_addr, jmpprd_addr;
126  struct cs5535audio_dma_desc *lastdesc;
127 
128  if (periods > CS5535AUDIO_MAX_DESCRIPTORS)
129  return -ENOMEM;
130 
131  if (dma->desc_buf.area == NULL) {
133  snd_dma_pci_data(cs5535au->pci),
135  &dma->desc_buf) < 0)
136  return -ENOMEM;
137  dma->period_bytes = dma->periods = 0;
138  }
139 
140  if (dma->periods == periods && dma->period_bytes == period_bytes)
141  return 0;
142 
143  /* the u32 cast is okay because in snd*create we successfully told
144  pci alloc that we're only 32 bit capable so the uppper will be 0 */
145  addr = (u32) substream->runtime->dma_addr;
146  desc_addr = (u32) dma->desc_buf.addr;
147  for (i = 0; i < periods; i++) {
148  struct cs5535audio_dma_desc *desc =
149  &((struct cs5535audio_dma_desc *) dma->desc_buf.area)[i];
150  desc->addr = cpu_to_le32(addr);
151  desc->size = cpu_to_le16(period_bytes);
153  desc_addr += sizeof(struct cs5535audio_dma_desc);
154  addr += period_bytes;
155  }
156  /* we reserved one dummy descriptor at the end to do the PRD jump */
157  lastdesc = &((struct cs5535audio_dma_desc *) dma->desc_buf.area)[periods];
158  lastdesc->addr = cpu_to_le32((u32) dma->desc_buf.addr);
159  lastdesc->size = 0;
160  lastdesc->ctlreserved = cpu_to_le16(PRD_JMP);
161  jmpprd_addr = cpu_to_le32(lastdesc->addr +
162  (sizeof(struct cs5535audio_dma_desc)*periods));
163 
164  dma->substream = substream;
165  dma->period_bytes = period_bytes;
166  dma->periods = periods;
167  spin_lock_irq(&cs5535au->reg_lock);
168  dma->ops->disable_dma(cs5535au);
169  dma->ops->setup_prd(cs5535au, jmpprd_addr);
170  spin_unlock_irq(&cs5535au->reg_lock);
171  return 0;
172 }
173 
174 static void cs5535audio_playback_enable_dma(struct cs5535audio *cs5535au)
175 {
176  cs_writeb(cs5535au, ACC_BM0_CMD, BM_CTL_EN);
177 }
178 
179 static void cs5535audio_playback_disable_dma(struct cs5535audio *cs5535au)
180 {
181  cs_writeb(cs5535au, ACC_BM0_CMD, 0);
182 }
183 
184 static void cs5535audio_playback_pause_dma(struct cs5535audio *cs5535au)
185 {
186  cs_writeb(cs5535au, ACC_BM0_CMD, BM_CTL_PAUSE);
187 }
188 
189 static void cs5535audio_playback_setup_prd(struct cs5535audio *cs5535au,
190  u32 prd_addr)
191 {
192  cs_writel(cs5535au, ACC_BM0_PRD, prd_addr);
193 }
194 
195 static u32 cs5535audio_playback_read_prd(struct cs5535audio *cs5535au)
196 {
197  return cs_readl(cs5535au, ACC_BM0_PRD);
198 }
199 
200 static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au)
201 {
202  return cs_readl(cs5535au, ACC_BM0_PNTR);
203 }
204 
205 static void cs5535audio_capture_enable_dma(struct cs5535audio *cs5535au)
206 {
207  cs_writeb(cs5535au, ACC_BM1_CMD, BM_CTL_EN);
208 }
209 
210 static void cs5535audio_capture_disable_dma(struct cs5535audio *cs5535au)
211 {
212  cs_writeb(cs5535au, ACC_BM1_CMD, 0);
213 }
214 
215 static void cs5535audio_capture_pause_dma(struct cs5535audio *cs5535au)
216 {
217  cs_writeb(cs5535au, ACC_BM1_CMD, BM_CTL_PAUSE);
218 }
219 
220 static void cs5535audio_capture_setup_prd(struct cs5535audio *cs5535au,
221  u32 prd_addr)
222 {
223  cs_writel(cs5535au, ACC_BM1_PRD, prd_addr);
224 }
225 
226 static u32 cs5535audio_capture_read_prd(struct cs5535audio *cs5535au)
227 {
228  return cs_readl(cs5535au, ACC_BM1_PRD);
229 }
230 
231 static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au)
232 {
233  return cs_readl(cs5535au, ACC_BM1_PNTR);
234 }
235 
236 static void cs5535audio_clear_dma_packets(struct cs5535audio *cs5535au,
237  struct cs5535audio_dma *dma,
238  struct snd_pcm_substream *substream)
239 {
241  dma->desc_buf.area = NULL;
242  dma->substream = NULL;
243 }
244 
245 static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream,
246  struct snd_pcm_hw_params *hw_params)
247 {
248  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
249  struct cs5535audio_dma *dma = substream->runtime->private_data;
250  int err;
251 
252  err = snd_pcm_lib_malloc_pages(substream,
253  params_buffer_bytes(hw_params));
254  if (err < 0)
255  return err;
256  dma->buf_addr = substream->runtime->dma_addr;
257  dma->buf_bytes = params_buffer_bytes(hw_params);
258 
259  err = cs5535audio_build_dma_packets(cs5535au, dma, substream,
260  params_periods(hw_params),
261  params_period_bytes(hw_params));
262  if (!err)
263  dma->pcm_open_flag = 1;
264 
265  return err;
266 }
267 
268 static int snd_cs5535audio_hw_free(struct snd_pcm_substream *substream)
269 {
270  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
271  struct cs5535audio_dma *dma = substream->runtime->private_data;
272 
273  if (dma->pcm_open_flag) {
274  if (substream == cs5535au->playback_substream)
275  snd_ac97_update_power(cs5535au->ac97,
277  else
278  snd_ac97_update_power(cs5535au->ac97,
280  dma->pcm_open_flag = 0;
281  }
282  cs5535audio_clear_dma_packets(cs5535au, dma, substream);
283  return snd_pcm_lib_free_pages(substream);
284 }
285 
286 static int snd_cs5535audio_playback_prepare(struct snd_pcm_substream *substream)
287 {
288  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
290  substream->runtime->rate);
291 }
292 
293 static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd)
294 {
295  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
296  struct cs5535audio_dma *dma = substream->runtime->private_data;
297  int err = 0;
298 
299  spin_lock(&cs5535au->reg_lock);
300  switch (cmd) {
302  dma->ops->pause_dma(cs5535au);
303  break;
305  dma->ops->enable_dma(cs5535au);
306  break;
308  dma->ops->enable_dma(cs5535au);
309  break;
311  dma->ops->enable_dma(cs5535au);
312  break;
314  dma->ops->disable_dma(cs5535au);
315  break;
317  dma->ops->disable_dma(cs5535au);
318  break;
319  default:
320  snd_printk(KERN_ERR "unhandled trigger\n");
321  err = -EINVAL;
322  break;
323  }
324  spin_unlock(&cs5535au->reg_lock);
325  return err;
326 }
327 
328 static snd_pcm_uframes_t snd_cs5535audio_pcm_pointer(struct snd_pcm_substream
329  *substream)
330 {
331  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
332  u32 curdma;
333  struct cs5535audio_dma *dma;
334 
335  dma = substream->runtime->private_data;
336  curdma = dma->ops->read_dma_pntr(cs5535au);
337  if (curdma < dma->buf_addr) {
338  snd_printk(KERN_ERR "curdma=%x < %x bufaddr.\n",
339  curdma, dma->buf_addr);
340  return 0;
341  }
342  curdma -= dma->buf_addr;
343  if (curdma >= dma->buf_bytes) {
344  snd_printk(KERN_ERR "diff=%x >= %x buf_bytes.\n",
345  curdma, dma->buf_bytes);
346  return 0;
347  }
348  return bytes_to_frames(substream->runtime, curdma);
349 }
350 
351 static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream)
352 {
353  int err;
354  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
355  struct snd_pcm_runtime *runtime = substream->runtime;
356 
357  runtime->hw = snd_cs5535audio_capture;
358  runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_ADC];
359  snd_pcm_limit_hw_rates(runtime);
360  cs5535au->capture_substream = substream;
361  runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]);
362  if ((err = snd_pcm_hw_constraint_integer(runtime,
364  return err;
365  olpc_capture_open(cs5535au->ac97);
366  return 0;
367 }
368 
369 static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream)
370 {
371  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
372  olpc_capture_close(cs5535au->ac97);
373  return 0;
374 }
375 
376 static int snd_cs5535audio_capture_prepare(struct snd_pcm_substream *substream)
377 {
378  struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream);
379  return snd_ac97_set_rate(cs5535au->ac97, AC97_PCM_LR_ADC_RATE,
380  substream->runtime->rate);
381 }
382 
383 static struct snd_pcm_ops snd_cs5535audio_playback_ops = {
384  .open = snd_cs5535audio_playback_open,
385  .close = snd_cs5535audio_playback_close,
386  .ioctl = snd_pcm_lib_ioctl,
387  .hw_params = snd_cs5535audio_hw_params,
388  .hw_free = snd_cs5535audio_hw_free,
389  .prepare = snd_cs5535audio_playback_prepare,
390  .trigger = snd_cs5535audio_trigger,
391  .pointer = snd_cs5535audio_pcm_pointer,
392 };
393 
394 static struct snd_pcm_ops snd_cs5535audio_capture_ops = {
395  .open = snd_cs5535audio_capture_open,
396  .close = snd_cs5535audio_capture_close,
397  .ioctl = snd_pcm_lib_ioctl,
398  .hw_params = snd_cs5535audio_hw_params,
399  .hw_free = snd_cs5535audio_hw_free,
400  .prepare = snd_cs5535audio_capture_prepare,
401  .trigger = snd_cs5535audio_trigger,
402  .pointer = snd_cs5535audio_pcm_pointer,
403 };
404 
405 static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = {
406  .type = CS5535AUDIO_DMA_PLAYBACK,
407  .enable_dma = cs5535audio_playback_enable_dma,
408  .disable_dma = cs5535audio_playback_disable_dma,
409  .setup_prd = cs5535audio_playback_setup_prd,
410  .read_prd = cs5535audio_playback_read_prd,
411  .pause_dma = cs5535audio_playback_pause_dma,
412  .read_dma_pntr = cs5535audio_playback_read_dma_pntr,
413 };
414 
415 static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = {
416  .type = CS5535AUDIO_DMA_CAPTURE,
417  .enable_dma = cs5535audio_capture_enable_dma,
418  .disable_dma = cs5535audio_capture_disable_dma,
419  .setup_prd = cs5535audio_capture_setup_prd,
420  .read_prd = cs5535audio_capture_read_prd,
421  .pause_dma = cs5535audio_capture_pause_dma,
422  .read_dma_pntr = cs5535audio_capture_read_dma_pntr,
423 };
424 
426 {
427  struct snd_pcm *pcm;
428  int err;
429 
430  err = snd_pcm_new(cs5535au->card, "CS5535 Audio", 0, 1, 1, &pcm);
431  if (err < 0)
432  return err;
433 
434  cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK].ops =
435  &snd_cs5535audio_playback_dma_ops;
436  cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE].ops =
437  &snd_cs5535audio_capture_dma_ops;
439  &snd_cs5535audio_playback_ops);
441  &snd_cs5535audio_capture_ops);
442 
443  pcm->private_data = cs5535au;
444  pcm->info_flags = 0;
445  strcpy(pcm->name, "CS5535 Audio");
446 
448  snd_dma_pci_data(cs5535au->pci),
449  64*1024, 128*1024);
450  cs5535au->pcm = pcm;
451 
452  return 0;
453 }
454