Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * Driver for Sound Core PDAudioCF soundcards | |
4 | * | |
5 | * PCM part | |
6 | * | |
c1017a4c | 7 | * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
8 | */ |
9 | ||
1da177e4 LT |
10 | #include <linux/delay.h> |
11 | #include <sound/core.h> | |
12 | #include <sound/asoundef.h> | |
13 | #include "pdaudiocf.h" | |
14 | ||
15 | ||
1da177e4 LT |
16 | /* |
17 | * clear the SRAM contents | |
18 | */ | |
db131548 | 19 | static int pdacf_pcm_clear_sram(struct snd_pdacf *chip) |
1da177e4 LT |
20 | { |
21 | int max_loop = 64 * 1024; | |
22 | ||
23 | while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) { | |
24 | if (max_loop-- < 0) | |
25 | return -EIO; | |
26 | inw(chip->port + PDAUDIOCF_REG_MD); | |
27 | } | |
28 | return 0; | |
29 | } | |
30 | ||
31 | /* | |
32 | * pdacf_pcm_trigger - trigger callback for capture | |
33 | */ | |
db131548 | 34 | static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) |
1da177e4 | 35 | { |
db131548 TI |
36 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); |
37 | struct snd_pcm_runtime *runtime = subs->runtime; | |
1da177e4 LT |
38 | int inc, ret = 0, rate; |
39 | unsigned short mask, val, tmp; | |
40 | ||
41 | if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) | |
42 | return -EBUSY; | |
43 | ||
44 | switch (cmd) { | |
45 | case SNDRV_PCM_TRIGGER_START: | |
46 | chip->pcm_hwptr = 0; | |
47 | chip->pcm_tdone = 0; | |
48 | /* fall thru */ | |
49 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
50 | case SNDRV_PCM_TRIGGER_RESUME: | |
51 | mask = 0; | |
52 | val = PDAUDIOCF_RECORD; | |
53 | inc = 1; | |
54 | rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE); | |
55 | break; | |
56 | case SNDRV_PCM_TRIGGER_STOP: | |
57 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
58 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
59 | mask = PDAUDIOCF_RECORD; | |
60 | val = 0; | |
61 | inc = -1; | |
62 | rate = 0; | |
63 | break; | |
64 | default: | |
65 | return -EINVAL; | |
66 | } | |
3b73cfe5 | 67 | mutex_lock(&chip->reg_lock); |
1da177e4 LT |
68 | chip->pcm_running += inc; |
69 | tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | |
70 | if (chip->pcm_running) { | |
71 | if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) { | |
72 | chip->pcm_running -= inc; | |
73 | ret = -EIO; | |
74 | goto __end; | |
75 | } | |
76 | } | |
77 | tmp &= ~mask; | |
78 | tmp |= val; | |
79 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp); | |
80 | __end: | |
3b73cfe5 | 81 | mutex_unlock(&chip->reg_lock); |
1da177e4 LT |
82 | snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE); |
83 | return ret; | |
84 | } | |
85 | ||
86 | /* | |
87 | * pdacf_pcm_hw_params - hw_params callback for playback and capture | |
88 | */ | |
db131548 TI |
89 | static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, |
90 | struct snd_pcm_hw_params *hw_params) | |
1da177e4 | 91 | { |
d20fb5dc CL |
92 | return snd_pcm_lib_alloc_vmalloc_32_buffer |
93 | (subs, params_buffer_bytes(hw_params)); | |
1da177e4 LT |
94 | } |
95 | ||
96 | /* | |
97 | * pdacf_pcm_hw_free - hw_free callback for playback and capture | |
98 | */ | |
db131548 | 99 | static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) |
1da177e4 | 100 | { |
d20fb5dc | 101 | return snd_pcm_lib_free_vmalloc_buffer(subs); |
1da177e4 LT |
102 | } |
103 | ||
104 | /* | |
105 | * pdacf_pcm_prepare - prepare callback for playback and capture | |
106 | */ | |
db131548 | 107 | static int pdacf_pcm_prepare(struct snd_pcm_substream *subs) |
1da177e4 | 108 | { |
db131548 TI |
109 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); |
110 | struct snd_pcm_runtime *runtime = subs->runtime; | |
1da177e4 LT |
111 | u16 val, nval, aval; |
112 | ||
113 | if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) | |
114 | return -EBUSY; | |
115 | ||
116 | chip->pcm_channels = runtime->channels; | |
117 | ||
118 | chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0; | |
119 | #ifdef SNDRV_LITTLE_ENDIAN | |
120 | chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0; | |
121 | #else | |
122 | chip->pcm_swab = chip->pcm_little; | |
123 | #endif | |
124 | ||
125 | if (snd_pcm_format_unsigned(runtime->format)) | |
126 | chip->pcm_xor = 0x80008000; | |
127 | ||
128 | if (pdacf_pcm_clear_sram(chip) < 0) | |
129 | return -EIO; | |
130 | ||
131 | val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | |
132 | nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1); | |
133 | switch (runtime->format) { | |
134 | case SNDRV_PCM_FORMAT_S16_LE: | |
135 | case SNDRV_PCM_FORMAT_S16_BE: | |
136 | break; | |
137 | default: /* 24-bit */ | |
138 | nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1; | |
139 | break; | |
140 | } | |
141 | aval = 0; | |
142 | chip->pcm_sample = 4; | |
143 | switch (runtime->format) { | |
144 | case SNDRV_PCM_FORMAT_S16_LE: | |
145 | case SNDRV_PCM_FORMAT_S16_BE: | |
146 | aval = AK4117_DIF_16R; | |
147 | chip->pcm_frame = 2; | |
148 | chip->pcm_sample = 2; | |
149 | break; | |
150 | case SNDRV_PCM_FORMAT_S24_3LE: | |
151 | case SNDRV_PCM_FORMAT_S24_3BE: | |
152 | chip->pcm_sample = 3; | |
93b1fae4 | 153 | /* fall through */ |
1da177e4 LT |
154 | default: /* 24-bit */ |
155 | aval = AK4117_DIF_24R; | |
156 | chip->pcm_frame = 3; | |
157 | chip->pcm_xor &= 0xffff0000; | |
158 | break; | |
159 | } | |
160 | ||
161 | if (val != nval) { | |
162 | snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval); | |
163 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval); | |
164 | } | |
165 | ||
166 | val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER); | |
167 | val &= ~(PDAUDIOCF_IRQLVLEN1); | |
168 | val |= PDAUDIOCF_IRQLVLEN0; | |
169 | pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val); | |
170 | ||
171 | chip->pcm_size = runtime->buffer_size; | |
172 | chip->pcm_period = runtime->period_size; | |
173 | chip->pcm_area = runtime->dma_area; | |
174 | ||
175 | return 0; | |
176 | } | |
177 | ||
178 | ||
179 | /* | |
180 | * capture hw information | |
181 | */ | |
182 | ||
d9b1b34f | 183 | static const struct snd_pcm_hardware pdacf_pcm_capture_hw = { |
1da177e4 LT |
184 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
185 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | | |
2008f137 TI |
186 | SNDRV_PCM_INFO_MMAP_VALID | |
187 | SNDRV_PCM_INFO_BATCH), | |
1da177e4 LT |
188 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | |
189 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | | |
190 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE, | |
191 | .rates = SNDRV_PCM_RATE_32000 | | |
192 | SNDRV_PCM_RATE_44100 | | |
193 | SNDRV_PCM_RATE_48000 | | |
194 | SNDRV_PCM_RATE_88200 | | |
195 | SNDRV_PCM_RATE_96000 | | |
196 | SNDRV_PCM_RATE_176400 | | |
197 | SNDRV_PCM_RATE_192000, | |
198 | .rate_min = 32000, | |
199 | .rate_max = 192000, | |
200 | .channels_min = 1, | |
201 | .channels_max = 2, | |
202 | .buffer_bytes_max = (512*1024), | |
203 | .period_bytes_min = 8*1024, | |
204 | .period_bytes_max = (64*1024), | |
205 | .periods_min = 2, | |
206 | .periods_max = 128, | |
207 | .fifo_size = 0, | |
208 | }; | |
209 | ||
210 | ||
211 | /* | |
212 | * pdacf_pcm_capture_open - open callback for capture | |
213 | */ | |
db131548 | 214 | static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs) |
1da177e4 | 215 | { |
db131548 TI |
216 | struct snd_pcm_runtime *runtime = subs->runtime; |
217 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); | |
1da177e4 LT |
218 | |
219 | if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) | |
220 | return -EBUSY; | |
221 | ||
222 | runtime->hw = pdacf_pcm_capture_hw; | |
223 | runtime->private_data = chip; | |
224 | chip->pcm_substream = subs; | |
225 | ||
226 | return 0; | |
227 | } | |
228 | ||
229 | /* | |
230 | * pdacf_pcm_capture_close - close callback for capture | |
231 | */ | |
db131548 | 232 | static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs) |
1da177e4 | 233 | { |
db131548 | 234 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); |
1da177e4 LT |
235 | |
236 | if (!chip) | |
237 | return -EINVAL; | |
238 | pdacf_reinit(chip, 0); | |
239 | chip->pcm_substream = NULL; | |
240 | return 0; | |
241 | } | |
242 | ||
243 | ||
244 | /* | |
245 | * pdacf_pcm_capture_pointer - pointer callback for capture | |
246 | */ | |
db131548 | 247 | static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs) |
1da177e4 | 248 | { |
db131548 | 249 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); |
1da177e4 LT |
250 | return chip->pcm_hwptr; |
251 | } | |
252 | ||
253 | /* | |
254 | * operators for PCM capture | |
255 | */ | |
e0c24d8b | 256 | static const struct snd_pcm_ops pdacf_pcm_capture_ops = { |
1da177e4 LT |
257 | .open = pdacf_pcm_capture_open, |
258 | .close = pdacf_pcm_capture_close, | |
259 | .ioctl = snd_pcm_lib_ioctl, | |
260 | .hw_params = pdacf_pcm_hw_params, | |
261 | .hw_free = pdacf_pcm_hw_free, | |
262 | .prepare = pdacf_pcm_prepare, | |
263 | .trigger = pdacf_pcm_trigger, | |
264 | .pointer = pdacf_pcm_capture_pointer, | |
d20fb5dc | 265 | .page = snd_pcm_lib_get_vmalloc_page, |
1da177e4 LT |
266 | }; |
267 | ||
268 | ||
1da177e4 LT |
269 | /* |
270 | * snd_pdacf_pcm_new - create and initialize a pcm | |
271 | */ | |
db131548 | 272 | int snd_pdacf_pcm_new(struct snd_pdacf *chip) |
1da177e4 | 273 | { |
db131548 | 274 | struct snd_pcm *pcm; |
1da177e4 LT |
275 | int err; |
276 | ||
277 | err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm); | |
278 | if (err < 0) | |
279 | return err; | |
280 | ||
281 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops); | |
282 | ||
283 | pcm->private_data = chip; | |
1da177e4 | 284 | pcm->info_flags = 0; |
3b73cfe5 | 285 | pcm->nonatomic = true; |
1da177e4 LT |
286 | strcpy(pcm->name, chip->card->shortname); |
287 | chip->pcm = pcm; | |
288 | ||
289 | err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | |
290 | if (err < 0) | |
291 | return err; | |
292 | ||
293 | return 0; | |
294 | } |