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; | |
c0dbbdad | 48 | fallthrough; |
1da177e4 LT |
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 | ||
1da177e4 LT |
86 | /* |
87 | * pdacf_pcm_prepare - prepare callback for playback and capture | |
88 | */ | |
db131548 | 89 | static int pdacf_pcm_prepare(struct snd_pcm_substream *subs) |
1da177e4 | 90 | { |
db131548 TI |
91 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); |
92 | struct snd_pcm_runtime *runtime = subs->runtime; | |
1da177e4 LT |
93 | u16 val, nval, aval; |
94 | ||
95 | if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) | |
96 | return -EBUSY; | |
97 | ||
98 | chip->pcm_channels = runtime->channels; | |
99 | ||
100 | chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0; | |
101 | #ifdef SNDRV_LITTLE_ENDIAN | |
102 | chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0; | |
103 | #else | |
104 | chip->pcm_swab = chip->pcm_little; | |
105 | #endif | |
106 | ||
107 | if (snd_pcm_format_unsigned(runtime->format)) | |
108 | chip->pcm_xor = 0x80008000; | |
109 | ||
110 | if (pdacf_pcm_clear_sram(chip) < 0) | |
111 | return -EIO; | |
112 | ||
113 | val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | |
114 | nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1); | |
115 | switch (runtime->format) { | |
116 | case SNDRV_PCM_FORMAT_S16_LE: | |
117 | case SNDRV_PCM_FORMAT_S16_BE: | |
118 | break; | |
119 | default: /* 24-bit */ | |
120 | nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1; | |
121 | break; | |
122 | } | |
123 | aval = 0; | |
124 | chip->pcm_sample = 4; | |
125 | switch (runtime->format) { | |
126 | case SNDRV_PCM_FORMAT_S16_LE: | |
127 | case SNDRV_PCM_FORMAT_S16_BE: | |
128 | aval = AK4117_DIF_16R; | |
129 | chip->pcm_frame = 2; | |
130 | chip->pcm_sample = 2; | |
131 | break; | |
132 | case SNDRV_PCM_FORMAT_S24_3LE: | |
133 | case SNDRV_PCM_FORMAT_S24_3BE: | |
134 | chip->pcm_sample = 3; | |
c0dbbdad | 135 | fallthrough; |
1da177e4 LT |
136 | default: /* 24-bit */ |
137 | aval = AK4117_DIF_24R; | |
138 | chip->pcm_frame = 3; | |
139 | chip->pcm_xor &= 0xffff0000; | |
140 | break; | |
141 | } | |
142 | ||
143 | if (val != nval) { | |
144 | snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval); | |
145 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval); | |
146 | } | |
147 | ||
148 | val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER); | |
149 | val &= ~(PDAUDIOCF_IRQLVLEN1); | |
150 | val |= PDAUDIOCF_IRQLVLEN0; | |
151 | pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val); | |
152 | ||
153 | chip->pcm_size = runtime->buffer_size; | |
154 | chip->pcm_period = runtime->period_size; | |
155 | chip->pcm_area = runtime->dma_area; | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | ||
161 | /* | |
162 | * capture hw information | |
163 | */ | |
164 | ||
d9b1b34f | 165 | static const struct snd_pcm_hardware pdacf_pcm_capture_hw = { |
1da177e4 LT |
166 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
167 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | | |
2008f137 TI |
168 | SNDRV_PCM_INFO_MMAP_VALID | |
169 | SNDRV_PCM_INFO_BATCH), | |
1da177e4 LT |
170 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | |
171 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | | |
172 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE, | |
173 | .rates = SNDRV_PCM_RATE_32000 | | |
174 | SNDRV_PCM_RATE_44100 | | |
175 | SNDRV_PCM_RATE_48000 | | |
176 | SNDRV_PCM_RATE_88200 | | |
177 | SNDRV_PCM_RATE_96000 | | |
178 | SNDRV_PCM_RATE_176400 | | |
179 | SNDRV_PCM_RATE_192000, | |
180 | .rate_min = 32000, | |
181 | .rate_max = 192000, | |
182 | .channels_min = 1, | |
183 | .channels_max = 2, | |
184 | .buffer_bytes_max = (512*1024), | |
185 | .period_bytes_min = 8*1024, | |
186 | .period_bytes_max = (64*1024), | |
187 | .periods_min = 2, | |
188 | .periods_max = 128, | |
189 | .fifo_size = 0, | |
190 | }; | |
191 | ||
192 | ||
193 | /* | |
194 | * pdacf_pcm_capture_open - open callback for capture | |
195 | */ | |
db131548 | 196 | static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs) |
1da177e4 | 197 | { |
db131548 TI |
198 | struct snd_pcm_runtime *runtime = subs->runtime; |
199 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); | |
1da177e4 LT |
200 | |
201 | if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) | |
202 | return -EBUSY; | |
203 | ||
204 | runtime->hw = pdacf_pcm_capture_hw; | |
205 | runtime->private_data = chip; | |
206 | chip->pcm_substream = subs; | |
207 | ||
208 | return 0; | |
209 | } | |
210 | ||
211 | /* | |
212 | * pdacf_pcm_capture_close - close callback for capture | |
213 | */ | |
db131548 | 214 | static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs) |
1da177e4 | 215 | { |
db131548 | 216 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); |
1da177e4 LT |
217 | |
218 | if (!chip) | |
219 | return -EINVAL; | |
220 | pdacf_reinit(chip, 0); | |
221 | chip->pcm_substream = NULL; | |
222 | return 0; | |
223 | } | |
224 | ||
225 | ||
226 | /* | |
227 | * pdacf_pcm_capture_pointer - pointer callback for capture | |
228 | */ | |
db131548 | 229 | static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs) |
1da177e4 | 230 | { |
db131548 | 231 | struct snd_pdacf *chip = snd_pcm_substream_chip(subs); |
1da177e4 LT |
232 | return chip->pcm_hwptr; |
233 | } | |
234 | ||
235 | /* | |
236 | * operators for PCM capture | |
237 | */ | |
e0c24d8b | 238 | static const struct snd_pcm_ops pdacf_pcm_capture_ops = { |
1da177e4 LT |
239 | .open = pdacf_pcm_capture_open, |
240 | .close = pdacf_pcm_capture_close, | |
1da177e4 LT |
241 | .prepare = pdacf_pcm_prepare, |
242 | .trigger = pdacf_pcm_trigger, | |
243 | .pointer = pdacf_pcm_capture_pointer, | |
1da177e4 LT |
244 | }; |
245 | ||
246 | ||
1da177e4 LT |
247 | /* |
248 | * snd_pdacf_pcm_new - create and initialize a pcm | |
249 | */ | |
db131548 | 250 | int snd_pdacf_pcm_new(struct snd_pdacf *chip) |
1da177e4 | 251 | { |
db131548 | 252 | struct snd_pcm *pcm; |
1da177e4 LT |
253 | int err; |
254 | ||
255 | err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm); | |
256 | if (err < 0) | |
257 | return err; | |
258 | ||
259 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops); | |
63bfc846 | 260 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, |
6dfa8fd5 | 261 | 0, 0); |
1da177e4 LT |
262 | |
263 | pcm->private_data = chip; | |
1da177e4 | 264 | pcm->info_flags = 0; |
3b73cfe5 | 265 | pcm->nonatomic = true; |
1da177e4 LT |
266 | strcpy(pcm->name, chip->card->shortname); |
267 | chip->pcm = pcm; | |
268 | ||
269 | err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | |
270 | if (err < 0) | |
271 | return err; | |
272 | ||
273 | return 0; | |
274 | } |