1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Driver for audio on multifunction CS5535 companion device
4 * Copyright (C) Jaya Kumar
6 * Based on Jaroslav Kysela and Takashi Iwai's examples.
7 * This work was sponsored by CIS(M) Sdn Bhd.
9 * todo: add be fmt support, spdif, pm
12 #include <linux/init.h>
13 #include <linux/pci.h>
14 #include <sound/core.h>
15 #include <sound/control.h>
16 #include <sound/initval.h>
17 #include <sound/asoundef.h>
18 #include <sound/pcm.h>
19 #include <sound/pcm_params.h>
20 #include <sound/ac97_codec.h>
21 #include "cs5535audio.h"
23 static const struct snd_pcm_hardware snd_cs5535audio_playback
=
27 SNDRV_PCM_INFO_INTERLEAVED
|
28 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
29 SNDRV_PCM_INFO_MMAP_VALID
|
30 SNDRV_PCM_INFO_PAUSE
|
34 SNDRV_PCM_FMTBIT_S16_LE
37 SNDRV_PCM_RATE_CONTINUOUS
|
38 SNDRV_PCM_RATE_8000_48000
44 .buffer_bytes_max
= (128*1024),
45 .period_bytes_min
= 64,
46 .period_bytes_max
= (64*1024 - 16),
48 .periods_max
= CS5535AUDIO_MAX_DESCRIPTORS
,
52 static const struct snd_pcm_hardware snd_cs5535audio_capture
=
56 SNDRV_PCM_INFO_INTERLEAVED
|
57 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
58 SNDRV_PCM_INFO_MMAP_VALID
61 SNDRV_PCM_FMTBIT_S16_LE
64 SNDRV_PCM_RATE_CONTINUOUS
|
65 SNDRV_PCM_RATE_8000_48000
71 .buffer_bytes_max
= (128*1024),
72 .period_bytes_min
= 64,
73 .period_bytes_max
= (64*1024 - 16),
75 .periods_max
= CS5535AUDIO_MAX_DESCRIPTORS
,
79 static int snd_cs5535audio_playback_open(struct snd_pcm_substream
*substream
)
82 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
83 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
85 runtime
->hw
= snd_cs5535audio_playback
;
86 runtime
->hw
.rates
= cs5535au
->ac97
->rates
[AC97_RATES_FRONT_DAC
];
87 snd_pcm_limit_hw_rates(runtime
);
88 cs5535au
->playback_substream
= substream
;
89 runtime
->private_data
= &(cs5535au
->dmas
[CS5535AUDIO_DMA_PLAYBACK
]);
90 if ((err
= snd_pcm_hw_constraint_integer(runtime
,
91 SNDRV_PCM_HW_PARAM_PERIODS
)) < 0)
97 static int snd_cs5535audio_playback_close(struct snd_pcm_substream
*substream
)
102 #define CS5535AUDIO_DESC_LIST_SIZE \
103 PAGE_ALIGN(CS5535AUDIO_MAX_DESCRIPTORS * sizeof(struct cs5535audio_dma_desc))
105 static int cs5535audio_build_dma_packets(struct cs5535audio
*cs5535au
,
106 struct cs5535audio_dma
*dma
,
107 struct snd_pcm_substream
*substream
,
108 unsigned int periods
,
109 unsigned int period_bytes
)
112 u32 addr
, desc_addr
, jmpprd_addr
;
113 struct cs5535audio_dma_desc
*lastdesc
;
115 if (periods
> CS5535AUDIO_MAX_DESCRIPTORS
)
118 if (dma
->desc_buf
.area
== NULL
) {
119 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
,
121 CS5535AUDIO_DESC_LIST_SIZE
+1,
124 dma
->period_bytes
= dma
->periods
= 0;
127 if (dma
->periods
== periods
&& dma
->period_bytes
== period_bytes
)
130 /* the u32 cast is okay because in snd*create we successfully told
131 pci alloc that we're only 32 bit capable so the uppper will be 0 */
132 addr
= (u32
) substream
->runtime
->dma_addr
;
133 desc_addr
= (u32
) dma
->desc_buf
.addr
;
134 for (i
= 0; i
< periods
; i
++) {
135 struct cs5535audio_dma_desc
*desc
=
136 &((struct cs5535audio_dma_desc
*) dma
->desc_buf
.area
)[i
];
137 desc
->addr
= cpu_to_le32(addr
);
138 desc
->size
= cpu_to_le16(period_bytes
);
139 desc
->ctlreserved
= cpu_to_le16(PRD_EOP
);
140 desc_addr
+= sizeof(struct cs5535audio_dma_desc
);
141 addr
+= period_bytes
;
143 /* we reserved one dummy descriptor at the end to do the PRD jump */
144 lastdesc
= &((struct cs5535audio_dma_desc
*) dma
->desc_buf
.area
)[periods
];
145 lastdesc
->addr
= cpu_to_le32((u32
) dma
->desc_buf
.addr
);
147 lastdesc
->ctlreserved
= cpu_to_le16(PRD_JMP
);
148 jmpprd_addr
= (u32
)dma
->desc_buf
.addr
+
149 sizeof(struct cs5535audio_dma_desc
) * periods
;
151 dma
->substream
= substream
;
152 dma
->period_bytes
= period_bytes
;
153 dma
->periods
= periods
;
154 spin_lock_irq(&cs5535au
->reg_lock
);
155 dma
->ops
->disable_dma(cs5535au
);
156 dma
->ops
->setup_prd(cs5535au
, jmpprd_addr
);
157 spin_unlock_irq(&cs5535au
->reg_lock
);
161 static void cs5535audio_playback_enable_dma(struct cs5535audio
*cs5535au
)
163 cs_writeb(cs5535au
, ACC_BM0_CMD
, BM_CTL_EN
);
166 static void cs5535audio_playback_disable_dma(struct cs5535audio
*cs5535au
)
168 cs_writeb(cs5535au
, ACC_BM0_CMD
, 0);
171 static void cs5535audio_playback_pause_dma(struct cs5535audio
*cs5535au
)
173 cs_writeb(cs5535au
, ACC_BM0_CMD
, BM_CTL_PAUSE
);
176 static void cs5535audio_playback_setup_prd(struct cs5535audio
*cs5535au
,
179 cs_writel(cs5535au
, ACC_BM0_PRD
, prd_addr
);
182 static u32
cs5535audio_playback_read_prd(struct cs5535audio
*cs5535au
)
184 return cs_readl(cs5535au
, ACC_BM0_PRD
);
187 static u32
cs5535audio_playback_read_dma_pntr(struct cs5535audio
*cs5535au
)
189 return cs_readl(cs5535au
, ACC_BM0_PNTR
);
192 static void cs5535audio_capture_enable_dma(struct cs5535audio
*cs5535au
)
194 cs_writeb(cs5535au
, ACC_BM1_CMD
, BM_CTL_EN
);
197 static void cs5535audio_capture_disable_dma(struct cs5535audio
*cs5535au
)
199 cs_writeb(cs5535au
, ACC_BM1_CMD
, 0);
202 static void cs5535audio_capture_pause_dma(struct cs5535audio
*cs5535au
)
204 cs_writeb(cs5535au
, ACC_BM1_CMD
, BM_CTL_PAUSE
);
207 static void cs5535audio_capture_setup_prd(struct cs5535audio
*cs5535au
,
210 cs_writel(cs5535au
, ACC_BM1_PRD
, prd_addr
);
213 static u32
cs5535audio_capture_read_prd(struct cs5535audio
*cs5535au
)
215 return cs_readl(cs5535au
, ACC_BM1_PRD
);
218 static u32
cs5535audio_capture_read_dma_pntr(struct cs5535audio
*cs5535au
)
220 return cs_readl(cs5535au
, ACC_BM1_PNTR
);
223 static void cs5535audio_clear_dma_packets(struct cs5535audio
*cs5535au
,
224 struct cs5535audio_dma
*dma
,
225 struct snd_pcm_substream
*substream
)
227 snd_dma_free_pages(&dma
->desc_buf
);
228 dma
->desc_buf
.area
= NULL
;
229 dma
->substream
= NULL
;
232 static int snd_cs5535audio_hw_params(struct snd_pcm_substream
*substream
,
233 struct snd_pcm_hw_params
*hw_params
)
235 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
236 struct cs5535audio_dma
*dma
= substream
->runtime
->private_data
;
239 err
= snd_pcm_lib_malloc_pages(substream
,
240 params_buffer_bytes(hw_params
));
243 dma
->buf_addr
= substream
->runtime
->dma_addr
;
244 dma
->buf_bytes
= params_buffer_bytes(hw_params
);
246 err
= cs5535audio_build_dma_packets(cs5535au
, dma
, substream
,
247 params_periods(hw_params
),
248 params_period_bytes(hw_params
));
250 dma
->pcm_open_flag
= 1;
255 static int snd_cs5535audio_hw_free(struct snd_pcm_substream
*substream
)
257 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
258 struct cs5535audio_dma
*dma
= substream
->runtime
->private_data
;
260 if (dma
->pcm_open_flag
) {
261 if (substream
== cs5535au
->playback_substream
)
262 snd_ac97_update_power(cs5535au
->ac97
,
263 AC97_PCM_FRONT_DAC_RATE
, 0);
265 snd_ac97_update_power(cs5535au
->ac97
,
266 AC97_PCM_LR_ADC_RATE
, 0);
267 dma
->pcm_open_flag
= 0;
269 cs5535audio_clear_dma_packets(cs5535au
, dma
, substream
);
270 return snd_pcm_lib_free_pages(substream
);
273 static int snd_cs5535audio_playback_prepare(struct snd_pcm_substream
*substream
)
275 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
276 return snd_ac97_set_rate(cs5535au
->ac97
, AC97_PCM_FRONT_DAC_RATE
,
277 substream
->runtime
->rate
);
280 static int snd_cs5535audio_trigger(struct snd_pcm_substream
*substream
, int cmd
)
282 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
283 struct cs5535audio_dma
*dma
= substream
->runtime
->private_data
;
286 spin_lock(&cs5535au
->reg_lock
);
288 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
289 dma
->ops
->pause_dma(cs5535au
);
291 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
292 dma
->ops
->enable_dma(cs5535au
);
294 case SNDRV_PCM_TRIGGER_START
:
295 dma
->ops
->enable_dma(cs5535au
);
297 case SNDRV_PCM_TRIGGER_RESUME
:
298 dma
->ops
->enable_dma(cs5535au
);
300 case SNDRV_PCM_TRIGGER_STOP
:
301 dma
->ops
->disable_dma(cs5535au
);
303 case SNDRV_PCM_TRIGGER_SUSPEND
:
304 dma
->ops
->disable_dma(cs5535au
);
307 dev_err(cs5535au
->card
->dev
, "unhandled trigger\n");
311 spin_unlock(&cs5535au
->reg_lock
);
315 static snd_pcm_uframes_t
snd_cs5535audio_pcm_pointer(struct snd_pcm_substream
318 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
320 struct cs5535audio_dma
*dma
;
322 dma
= substream
->runtime
->private_data
;
323 curdma
= dma
->ops
->read_dma_pntr(cs5535au
);
324 if (curdma
< dma
->buf_addr
) {
325 dev_err(cs5535au
->card
->dev
, "curdma=%x < %x bufaddr.\n",
326 curdma
, dma
->buf_addr
);
329 curdma
-= dma
->buf_addr
;
330 if (curdma
>= dma
->buf_bytes
) {
331 dev_err(cs5535au
->card
->dev
, "diff=%x >= %x buf_bytes.\n",
332 curdma
, dma
->buf_bytes
);
335 return bytes_to_frames(substream
->runtime
, curdma
);
338 static int snd_cs5535audio_capture_open(struct snd_pcm_substream
*substream
)
341 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
342 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
344 runtime
->hw
= snd_cs5535audio_capture
;
345 runtime
->hw
.rates
= cs5535au
->ac97
->rates
[AC97_RATES_ADC
];
346 snd_pcm_limit_hw_rates(runtime
);
347 cs5535au
->capture_substream
= substream
;
348 runtime
->private_data
= &(cs5535au
->dmas
[CS5535AUDIO_DMA_CAPTURE
]);
349 if ((err
= snd_pcm_hw_constraint_integer(runtime
,
350 SNDRV_PCM_HW_PARAM_PERIODS
)) < 0)
352 olpc_capture_open(cs5535au
->ac97
);
356 static int snd_cs5535audio_capture_close(struct snd_pcm_substream
*substream
)
358 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
359 olpc_capture_close(cs5535au
->ac97
);
363 static int snd_cs5535audio_capture_prepare(struct snd_pcm_substream
*substream
)
365 struct cs5535audio
*cs5535au
= snd_pcm_substream_chip(substream
);
366 return snd_ac97_set_rate(cs5535au
->ac97
, AC97_PCM_LR_ADC_RATE
,
367 substream
->runtime
->rate
);
370 static const struct snd_pcm_ops snd_cs5535audio_playback_ops
= {
371 .open
= snd_cs5535audio_playback_open
,
372 .close
= snd_cs5535audio_playback_close
,
373 .ioctl
= snd_pcm_lib_ioctl
,
374 .hw_params
= snd_cs5535audio_hw_params
,
375 .hw_free
= snd_cs5535audio_hw_free
,
376 .prepare
= snd_cs5535audio_playback_prepare
,
377 .trigger
= snd_cs5535audio_trigger
,
378 .pointer
= snd_cs5535audio_pcm_pointer
,
381 static const struct snd_pcm_ops snd_cs5535audio_capture_ops
= {
382 .open
= snd_cs5535audio_capture_open
,
383 .close
= snd_cs5535audio_capture_close
,
384 .ioctl
= snd_pcm_lib_ioctl
,
385 .hw_params
= snd_cs5535audio_hw_params
,
386 .hw_free
= snd_cs5535audio_hw_free
,
387 .prepare
= snd_cs5535audio_capture_prepare
,
388 .trigger
= snd_cs5535audio_trigger
,
389 .pointer
= snd_cs5535audio_pcm_pointer
,
392 static const struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops
= {
393 .type
= CS5535AUDIO_DMA_PLAYBACK
,
394 .enable_dma
= cs5535audio_playback_enable_dma
,
395 .disable_dma
= cs5535audio_playback_disable_dma
,
396 .setup_prd
= cs5535audio_playback_setup_prd
,
397 .read_prd
= cs5535audio_playback_read_prd
,
398 .pause_dma
= cs5535audio_playback_pause_dma
,
399 .read_dma_pntr
= cs5535audio_playback_read_dma_pntr
,
402 static const struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops
= {
403 .type
= CS5535AUDIO_DMA_CAPTURE
,
404 .enable_dma
= cs5535audio_capture_enable_dma
,
405 .disable_dma
= cs5535audio_capture_disable_dma
,
406 .setup_prd
= cs5535audio_capture_setup_prd
,
407 .read_prd
= cs5535audio_capture_read_prd
,
408 .pause_dma
= cs5535audio_capture_pause_dma
,
409 .read_dma_pntr
= cs5535audio_capture_read_dma_pntr
,
412 int snd_cs5535audio_pcm(struct cs5535audio
*cs5535au
)
417 err
= snd_pcm_new(cs5535au
->card
, "CS5535 Audio", 0, 1, 1, &pcm
);
421 cs5535au
->dmas
[CS5535AUDIO_DMA_PLAYBACK
].ops
=
422 &snd_cs5535audio_playback_dma_ops
;
423 cs5535au
->dmas
[CS5535AUDIO_DMA_CAPTURE
].ops
=
424 &snd_cs5535audio_capture_dma_ops
;
425 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
,
426 &snd_cs5535audio_playback_ops
);
427 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
,
428 &snd_cs5535audio_capture_ops
);
430 pcm
->private_data
= cs5535au
;
432 strcpy(pcm
->name
, "CS5535 Audio");
434 snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_DEV
,