1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Routines for control of the AK4114 via I2C and 4-wire serial interface |
4 | * IEC958 (S/PDIF) receiver by Asahi Kasei |
5 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
6 | */ |
7 | |
8 | #include <linux/slab.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/module.h> |
11 | #include <sound/core.h> |
12 | #include <sound/control.h> |
13 | #include <sound/pcm.h> |
14 | #include <sound/ak4114.h> |
15 | #include <sound/asoundef.h> |
16 | #include <sound/info.h> |
17 | |
18 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>" ); |
19 | MODULE_DESCRIPTION("AK4114 IEC958 (S/PDIF) receiver by Asahi Kasei" ); |
20 | MODULE_LICENSE("GPL" ); |
21 | |
22 | #define AK4114_ADDR 0x00 /* fixed address */ |
23 | |
24 | static void ak4114_stats(struct work_struct *work); |
25 | static void ak4114_init_regs(struct ak4114 *chip); |
26 | |
27 | static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char val) |
28 | { |
29 | ak4114->write(ak4114->private_data, reg, val); |
30 | if (reg <= AK4114_REG_INT1_MASK) |
31 | ak4114->regmap[reg] = val; |
32 | else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) |
33 | ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val; |
34 | } |
35 | |
36 | static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg) |
37 | { |
38 | return ak4114->read(ak4114->private_data, reg); |
39 | } |
40 | |
41 | #if 0 |
42 | static void reg_dump(struct ak4114 *ak4114) |
43 | { |
44 | int i; |
45 | |
46 | printk(KERN_DEBUG "AK4114 REG DUMP:\n" ); |
47 | for (i = 0; i < 0x20; i++) |
48 | printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n" , i, reg_read(ak4114, i), i < ARRAY_SIZE(ak4114->regmap) ? ak4114->regmap[i] : 0); |
49 | } |
50 | #endif |
51 | |
52 | static void snd_ak4114_free(struct ak4114 *chip) |
53 | { |
54 | atomic_inc(v: &chip->wq_processing); /* don't schedule new work */ |
55 | cancel_delayed_work_sync(dwork: &chip->work); |
56 | kfree(objp: chip); |
57 | } |
58 | |
59 | static int snd_ak4114_dev_free(struct snd_device *device) |
60 | { |
61 | struct ak4114 *chip = device->device_data; |
62 | snd_ak4114_free(chip); |
63 | return 0; |
64 | } |
65 | |
66 | int snd_ak4114_create(struct snd_card *card, |
67 | ak4114_read_t *read, ak4114_write_t *write, |
68 | const unsigned char pgm[6], const unsigned char txcsb[5], |
69 | void *private_data, struct ak4114 **r_ak4114) |
70 | { |
71 | struct ak4114 *chip; |
72 | int err = 0; |
73 | unsigned char reg; |
74 | static const struct snd_device_ops ops = { |
75 | .dev_free = snd_ak4114_dev_free, |
76 | }; |
77 | |
78 | chip = kzalloc(size: sizeof(*chip), GFP_KERNEL); |
79 | if (chip == NULL) |
80 | return -ENOMEM; |
81 | spin_lock_init(&chip->lock); |
82 | chip->card = card; |
83 | chip->read = read; |
84 | chip->write = write; |
85 | chip->private_data = private_data; |
86 | INIT_DELAYED_WORK(&chip->work, ak4114_stats); |
87 | atomic_set(v: &chip->wq_processing, i: 0); |
88 | mutex_init(&chip->reinit_mutex); |
89 | |
90 | for (reg = 0; reg < 6; reg++) |
91 | chip->regmap[reg] = pgm[reg]; |
92 | for (reg = 0; reg < 5; reg++) |
93 | chip->txcsb[reg] = txcsb[reg]; |
94 | |
95 | ak4114_init_regs(chip); |
96 | |
97 | chip->rcs0 = reg_read(ak4114: chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); |
98 | chip->rcs1 = reg_read(ak4114: chip, AK4114_REG_RCS1); |
99 | |
100 | err = snd_device_new(card, type: SNDRV_DEV_CODEC, device_data: chip, ops: &ops); |
101 | if (err < 0) |
102 | goto __fail; |
103 | |
104 | if (r_ak4114) |
105 | *r_ak4114 = chip; |
106 | return 0; |
107 | |
108 | __fail: |
109 | snd_ak4114_free(chip); |
110 | return err; |
111 | } |
112 | EXPORT_SYMBOL(snd_ak4114_create); |
113 | |
114 | void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char mask, unsigned char val) |
115 | { |
116 | if (reg <= AK4114_REG_INT1_MASK) |
117 | reg_write(ak4114: chip, reg, val: (chip->regmap[reg] & ~mask) | val); |
118 | else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) |
119 | reg_write(ak4114: chip, reg, |
120 | val: (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val); |
121 | } |
122 | EXPORT_SYMBOL(snd_ak4114_reg_write); |
123 | |
124 | static void ak4114_init_regs(struct ak4114 *chip) |
125 | { |
126 | unsigned char old = chip->regmap[AK4114_REG_PWRDN], reg; |
127 | |
128 | /* bring the chip to reset state and powerdown state */ |
129 | reg_write(ak4114: chip, AK4114_REG_PWRDN, val: old & ~(AK4114_RST|AK4114_PWN)); |
130 | udelay(200); |
131 | /* release reset, but leave powerdown */ |
132 | reg_write(ak4114: chip, AK4114_REG_PWRDN, val: (old | AK4114_RST) & ~AK4114_PWN); |
133 | udelay(200); |
134 | for (reg = 1; reg < 6; reg++) |
135 | reg_write(ak4114: chip, reg, val: chip->regmap[reg]); |
136 | for (reg = 0; reg < 5; reg++) |
137 | reg_write(ak4114: chip, reg: reg + AK4114_REG_TXCSB0, val: chip->txcsb[reg]); |
138 | /* release powerdown, everything is initialized now */ |
139 | reg_write(ak4114: chip, AK4114_REG_PWRDN, val: old | AK4114_RST | AK4114_PWN); |
140 | } |
141 | |
142 | void snd_ak4114_reinit(struct ak4114 *chip) |
143 | { |
144 | if (atomic_inc_return(v: &chip->wq_processing) == 1) |
145 | cancel_delayed_work_sync(dwork: &chip->work); |
146 | mutex_lock(&chip->reinit_mutex); |
147 | ak4114_init_regs(chip); |
148 | mutex_unlock(lock: &chip->reinit_mutex); |
149 | /* bring up statistics / event queing */ |
150 | if (atomic_dec_and_test(v: &chip->wq_processing)) |
151 | schedule_delayed_work(dwork: &chip->work, HZ / 10); |
152 | } |
153 | EXPORT_SYMBOL(snd_ak4114_reinit); |
154 | |
155 | static unsigned int external_rate(unsigned char rcs1) |
156 | { |
157 | switch (rcs1 & (AK4114_FS0|AK4114_FS1|AK4114_FS2|AK4114_FS3)) { |
158 | case AK4114_FS_32000HZ: return 32000; |
159 | case AK4114_FS_44100HZ: return 44100; |
160 | case AK4114_FS_48000HZ: return 48000; |
161 | case AK4114_FS_88200HZ: return 88200; |
162 | case AK4114_FS_96000HZ: return 96000; |
163 | case AK4114_FS_176400HZ: return 176400; |
164 | case AK4114_FS_192000HZ: return 192000; |
165 | default: return 0; |
166 | } |
167 | } |
168 | |
169 | static int snd_ak4114_in_error_info(struct snd_kcontrol *kcontrol, |
170 | struct snd_ctl_elem_info *uinfo) |
171 | { |
172 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
173 | uinfo->count = 1; |
174 | uinfo->value.integer.min = 0; |
175 | uinfo->value.integer.max = LONG_MAX; |
176 | return 0; |
177 | } |
178 | |
179 | static int snd_ak4114_in_error_get(struct snd_kcontrol *kcontrol, |
180 | struct snd_ctl_elem_value *ucontrol) |
181 | { |
182 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
183 | |
184 | spin_lock_irq(lock: &chip->lock); |
185 | ucontrol->value.integer.value[0] = |
186 | chip->errors[kcontrol->private_value]; |
187 | chip->errors[kcontrol->private_value] = 0; |
188 | spin_unlock_irq(lock: &chip->lock); |
189 | return 0; |
190 | } |
191 | |
192 | #define snd_ak4114_in_bit_info snd_ctl_boolean_mono_info |
193 | |
194 | static int snd_ak4114_in_bit_get(struct snd_kcontrol *kcontrol, |
195 | struct snd_ctl_elem_value *ucontrol) |
196 | { |
197 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
198 | unsigned char reg = kcontrol->private_value & 0xff; |
199 | unsigned char bit = (kcontrol->private_value >> 8) & 0xff; |
200 | unsigned char inv = (kcontrol->private_value >> 31) & 1; |
201 | |
202 | ucontrol->value.integer.value[0] = ((reg_read(ak4114: chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; |
203 | return 0; |
204 | } |
205 | |
206 | static int snd_ak4114_rate_info(struct snd_kcontrol *kcontrol, |
207 | struct snd_ctl_elem_info *uinfo) |
208 | { |
209 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
210 | uinfo->count = 1; |
211 | uinfo->value.integer.min = 0; |
212 | uinfo->value.integer.max = 192000; |
213 | return 0; |
214 | } |
215 | |
216 | static int snd_ak4114_rate_get(struct snd_kcontrol *kcontrol, |
217 | struct snd_ctl_elem_value *ucontrol) |
218 | { |
219 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
220 | |
221 | ucontrol->value.integer.value[0] = external_rate(rcs1: reg_read(ak4114: chip, AK4114_REG_RCS1)); |
222 | return 0; |
223 | } |
224 | |
225 | static int snd_ak4114_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
226 | { |
227 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
228 | uinfo->count = 1; |
229 | return 0; |
230 | } |
231 | |
232 | static int snd_ak4114_spdif_get(struct snd_kcontrol *kcontrol, |
233 | struct snd_ctl_elem_value *ucontrol) |
234 | { |
235 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
236 | unsigned i; |
237 | |
238 | for (i = 0; i < AK4114_REG_RXCSB_SIZE; i++) |
239 | ucontrol->value.iec958.status[i] = reg_read(ak4114: chip, AK4114_REG_RXCSB0 + i); |
240 | return 0; |
241 | } |
242 | |
243 | static int snd_ak4114_spdif_playback_get(struct snd_kcontrol *kcontrol, |
244 | struct snd_ctl_elem_value *ucontrol) |
245 | { |
246 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
247 | unsigned i; |
248 | |
249 | for (i = 0; i < AK4114_REG_TXCSB_SIZE; i++) |
250 | ucontrol->value.iec958.status[i] = chip->txcsb[i]; |
251 | return 0; |
252 | } |
253 | |
254 | static int snd_ak4114_spdif_playback_put(struct snd_kcontrol *kcontrol, |
255 | struct snd_ctl_elem_value *ucontrol) |
256 | { |
257 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
258 | unsigned i; |
259 | |
260 | for (i = 0; i < AK4114_REG_TXCSB_SIZE; i++) |
261 | reg_write(ak4114: chip, AK4114_REG_TXCSB0 + i, val: ucontrol->value.iec958.status[i]); |
262 | return 0; |
263 | } |
264 | |
265 | static int snd_ak4114_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
266 | { |
267 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
268 | uinfo->count = 1; |
269 | return 0; |
270 | } |
271 | |
272 | static int snd_ak4114_spdif_mask_get(struct snd_kcontrol *kcontrol, |
273 | struct snd_ctl_elem_value *ucontrol) |
274 | { |
275 | memset(ucontrol->value.iec958.status, 0xff, AK4114_REG_RXCSB_SIZE); |
276 | return 0; |
277 | } |
278 | |
279 | static int snd_ak4114_spdif_pinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
280 | { |
281 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
282 | uinfo->value.integer.min = 0; |
283 | uinfo->value.integer.max = 0xffff; |
284 | uinfo->count = 4; |
285 | return 0; |
286 | } |
287 | |
288 | static int snd_ak4114_spdif_pget(struct snd_kcontrol *kcontrol, |
289 | struct snd_ctl_elem_value *ucontrol) |
290 | { |
291 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
292 | unsigned short tmp; |
293 | |
294 | ucontrol->value.integer.value[0] = 0xf8f2; |
295 | ucontrol->value.integer.value[1] = 0x4e1f; |
296 | tmp = reg_read(ak4114: chip, AK4114_REG_Pc0) | (reg_read(ak4114: chip, AK4114_REG_Pc1) << 8); |
297 | ucontrol->value.integer.value[2] = tmp; |
298 | tmp = reg_read(ak4114: chip, AK4114_REG_Pd0) | (reg_read(ak4114: chip, AK4114_REG_Pd1) << 8); |
299 | ucontrol->value.integer.value[3] = tmp; |
300 | return 0; |
301 | } |
302 | |
303 | static int snd_ak4114_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
304 | { |
305 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; |
306 | uinfo->count = AK4114_REG_QSUB_SIZE; |
307 | return 0; |
308 | } |
309 | |
310 | static int snd_ak4114_spdif_qget(struct snd_kcontrol *kcontrol, |
311 | struct snd_ctl_elem_value *ucontrol) |
312 | { |
313 | struct ak4114 *chip = snd_kcontrol_chip(kcontrol); |
314 | unsigned i; |
315 | |
316 | for (i = 0; i < AK4114_REG_QSUB_SIZE; i++) |
317 | ucontrol->value.bytes.data[i] = reg_read(ak4114: chip, AK4114_REG_QSUB_ADDR + i); |
318 | return 0; |
319 | } |
320 | |
321 | /* Don't forget to change AK4114_CONTROLS define!!! */ |
322 | static const struct snd_kcontrol_new snd_ak4114_iec958_controls[] = { |
323 | { |
324 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
325 | .name = "IEC958 Parity Errors" , |
326 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
327 | .info = snd_ak4114_in_error_info, |
328 | .get = snd_ak4114_in_error_get, |
329 | .private_value = AK4114_PARITY_ERRORS, |
330 | }, |
331 | { |
332 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
333 | .name = "IEC958 V-Bit Errors" , |
334 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
335 | .info = snd_ak4114_in_error_info, |
336 | .get = snd_ak4114_in_error_get, |
337 | .private_value = AK4114_V_BIT_ERRORS, |
338 | }, |
339 | { |
340 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
341 | .name = "IEC958 C-CRC Errors" , |
342 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
343 | .info = snd_ak4114_in_error_info, |
344 | .get = snd_ak4114_in_error_get, |
345 | .private_value = AK4114_CCRC_ERRORS, |
346 | }, |
347 | { |
348 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
349 | .name = "IEC958 Q-CRC Errors" , |
350 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
351 | .info = snd_ak4114_in_error_info, |
352 | .get = snd_ak4114_in_error_get, |
353 | .private_value = AK4114_QCRC_ERRORS, |
354 | }, |
355 | { |
356 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
357 | .name = "IEC958 External Rate" , |
358 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
359 | .info = snd_ak4114_rate_info, |
360 | .get = snd_ak4114_rate_get, |
361 | }, |
362 | { |
363 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
364 | .name = SNDRV_CTL_NAME_IEC958("" ,PLAYBACK,MASK), |
365 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
366 | .info = snd_ak4114_spdif_mask_info, |
367 | .get = snd_ak4114_spdif_mask_get, |
368 | }, |
369 | { |
370 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
371 | .name = SNDRV_CTL_NAME_IEC958("" ,PLAYBACK,DEFAULT), |
372 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
373 | .info = snd_ak4114_spdif_info, |
374 | .get = snd_ak4114_spdif_playback_get, |
375 | .put = snd_ak4114_spdif_playback_put, |
376 | }, |
377 | { |
378 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
379 | .name = SNDRV_CTL_NAME_IEC958("" ,CAPTURE,MASK), |
380 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
381 | .info = snd_ak4114_spdif_mask_info, |
382 | .get = snd_ak4114_spdif_mask_get, |
383 | }, |
384 | { |
385 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
386 | .name = SNDRV_CTL_NAME_IEC958("" ,CAPTURE,DEFAULT), |
387 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
388 | .info = snd_ak4114_spdif_info, |
389 | .get = snd_ak4114_spdif_get, |
390 | }, |
391 | { |
392 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
393 | .name = "IEC958 Preamble Capture Default" , |
394 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
395 | .info = snd_ak4114_spdif_pinfo, |
396 | .get = snd_ak4114_spdif_pget, |
397 | }, |
398 | { |
399 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
400 | .name = "IEC958 Q-subcode Capture Default" , |
401 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
402 | .info = snd_ak4114_spdif_qinfo, |
403 | .get = snd_ak4114_spdif_qget, |
404 | }, |
405 | { |
406 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
407 | .name = "IEC958 Audio" , |
408 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
409 | .info = snd_ak4114_in_bit_info, |
410 | .get = snd_ak4114_in_bit_get, |
411 | .private_value = (1<<31) | (1<<8) | AK4114_REG_RCS0, |
412 | }, |
413 | { |
414 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
415 | .name = "IEC958 Non-PCM Bitstream" , |
416 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
417 | .info = snd_ak4114_in_bit_info, |
418 | .get = snd_ak4114_in_bit_get, |
419 | .private_value = (6<<8) | AK4114_REG_RCS0, |
420 | }, |
421 | { |
422 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
423 | .name = "IEC958 DTS Bitstream" , |
424 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
425 | .info = snd_ak4114_in_bit_info, |
426 | .get = snd_ak4114_in_bit_get, |
427 | .private_value = (3<<8) | AK4114_REG_RCS0, |
428 | }, |
429 | { |
430 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
431 | .name = "IEC958 PPL Lock Status" , |
432 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
433 | .info = snd_ak4114_in_bit_info, |
434 | .get = snd_ak4114_in_bit_get, |
435 | .private_value = (1<<31) | (4<<8) | AK4114_REG_RCS0, |
436 | } |
437 | }; |
438 | |
439 | |
440 | static void snd_ak4114_proc_regs_read(struct snd_info_entry *entry, |
441 | struct snd_info_buffer *buffer) |
442 | { |
443 | struct ak4114 *ak4114 = entry->private_data; |
444 | int reg, val; |
445 | /* all ak4114 registers 0x00 - 0x1f */ |
446 | for (reg = 0; reg < 0x20; reg++) { |
447 | val = reg_read(ak4114, reg); |
448 | snd_iprintf(buffer, "0x%02x = 0x%02x\n" , reg, val); |
449 | } |
450 | } |
451 | |
452 | static void snd_ak4114_proc_init(struct ak4114 *ak4114) |
453 | { |
454 | snd_card_ro_proc_new(card: ak4114->card, name: "ak4114" , private_data: ak4114, |
455 | read: snd_ak4114_proc_regs_read); |
456 | } |
457 | |
458 | int snd_ak4114_build(struct ak4114 *ak4114, |
459 | struct snd_pcm_substream *ply_substream, |
460 | struct snd_pcm_substream *cap_substream) |
461 | { |
462 | struct snd_kcontrol *kctl; |
463 | unsigned int idx; |
464 | int err; |
465 | |
466 | if (snd_BUG_ON(!cap_substream)) |
467 | return -EINVAL; |
468 | ak4114->playback_substream = ply_substream; |
469 | ak4114->capture_substream = cap_substream; |
470 | for (idx = 0; idx < AK4114_CONTROLS; idx++) { |
471 | kctl = snd_ctl_new1(kcontrolnew: &snd_ak4114_iec958_controls[idx], private_data: ak4114); |
472 | if (kctl == NULL) |
473 | return -ENOMEM; |
474 | if (strstr(kctl->id.name, "Playback" )) { |
475 | if (ply_substream == NULL) { |
476 | snd_ctl_free_one(kcontrol: kctl); |
477 | ak4114->kctls[idx] = NULL; |
478 | continue; |
479 | } |
480 | kctl->id.device = ply_substream->pcm->device; |
481 | kctl->id.subdevice = ply_substream->number; |
482 | } else { |
483 | kctl->id.device = cap_substream->pcm->device; |
484 | kctl->id.subdevice = cap_substream->number; |
485 | } |
486 | err = snd_ctl_add(card: ak4114->card, kcontrol: kctl); |
487 | if (err < 0) |
488 | return err; |
489 | ak4114->kctls[idx] = kctl; |
490 | } |
491 | snd_ak4114_proc_init(ak4114); |
492 | /* trigger workq */ |
493 | schedule_delayed_work(dwork: &ak4114->work, HZ / 10); |
494 | return 0; |
495 | } |
496 | EXPORT_SYMBOL(snd_ak4114_build); |
497 | |
498 | /* notify kcontrols if any parameters are changed */ |
499 | static void ak4114_notify(struct ak4114 *ak4114, |
500 | unsigned char rcs0, unsigned char rcs1, |
501 | unsigned char c0, unsigned char c1) |
502 | { |
503 | if (!ak4114->kctls[0]) |
504 | return; |
505 | |
506 | if (rcs0 & AK4114_PAR) |
507 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
508 | id: &ak4114->kctls[0]->id); |
509 | if (rcs0 & AK4114_V) |
510 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
511 | id: &ak4114->kctls[1]->id); |
512 | if (rcs1 & AK4114_CCRC) |
513 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
514 | id: &ak4114->kctls[2]->id); |
515 | if (rcs1 & AK4114_QCRC) |
516 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
517 | id: &ak4114->kctls[3]->id); |
518 | |
519 | /* rate change */ |
520 | if (c1 & 0xf0) |
521 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
522 | id: &ak4114->kctls[4]->id); |
523 | |
524 | if ((c0 & AK4114_PEM) | (c0 & AK4114_CINT)) |
525 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
526 | id: &ak4114->kctls[9]->id); |
527 | if (c0 & AK4114_QINT) |
528 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
529 | id: &ak4114->kctls[10]->id); |
530 | |
531 | if (c0 & AK4114_AUDION) |
532 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
533 | id: &ak4114->kctls[11]->id); |
534 | if (c0 & AK4114_AUTO) |
535 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
536 | id: &ak4114->kctls[12]->id); |
537 | if (c0 & AK4114_DTSCD) |
538 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
539 | id: &ak4114->kctls[13]->id); |
540 | if (c0 & AK4114_UNLCK) |
541 | snd_ctl_notify(card: ak4114->card, SNDRV_CTL_EVENT_MASK_VALUE, |
542 | id: &ak4114->kctls[14]->id); |
543 | } |
544 | |
545 | int snd_ak4114_external_rate(struct ak4114 *ak4114) |
546 | { |
547 | unsigned char rcs1; |
548 | |
549 | rcs1 = reg_read(ak4114, AK4114_REG_RCS1); |
550 | return external_rate(rcs1); |
551 | } |
552 | EXPORT_SYMBOL(snd_ak4114_external_rate); |
553 | |
554 | int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags) |
555 | { |
556 | struct snd_pcm_runtime *runtime = ak4114->capture_substream ? ak4114->capture_substream->runtime : NULL; |
557 | unsigned long _flags; |
558 | int res = 0; |
559 | unsigned char rcs0, rcs1; |
560 | unsigned char c0, c1; |
561 | |
562 | rcs1 = reg_read(ak4114, AK4114_REG_RCS1); |
563 | if (flags & AK4114_CHECK_NO_STAT) |
564 | goto __rate; |
565 | rcs0 = reg_read(ak4114, AK4114_REG_RCS0); |
566 | spin_lock_irqsave(&ak4114->lock, _flags); |
567 | if (rcs0 & AK4114_PAR) |
568 | ak4114->errors[AK4114_PARITY_ERRORS]++; |
569 | if (rcs1 & AK4114_V) |
570 | ak4114->errors[AK4114_V_BIT_ERRORS]++; |
571 | if (rcs1 & AK4114_CCRC) |
572 | ak4114->errors[AK4114_CCRC_ERRORS]++; |
573 | if (rcs1 & AK4114_QCRC) |
574 | ak4114->errors[AK4114_QCRC_ERRORS]++; |
575 | c0 = (ak4114->rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)) ^ |
576 | (rcs0 & (AK4114_QINT | AK4114_CINT | AK4114_PEM | AK4114_AUDION | AK4114_AUTO | AK4114_UNLCK)); |
577 | c1 = (ak4114->rcs1 & 0xf0) ^ (rcs1 & 0xf0); |
578 | ak4114->rcs0 = rcs0 & ~(AK4114_QINT | AK4114_CINT); |
579 | ak4114->rcs1 = rcs1; |
580 | spin_unlock_irqrestore(lock: &ak4114->lock, flags: _flags); |
581 | |
582 | ak4114_notify(ak4114, rcs0, rcs1, c0, c1); |
583 | if (ak4114->change_callback && (c0 | c1) != 0) |
584 | ak4114->change_callback(ak4114, c0, c1); |
585 | |
586 | __rate: |
587 | /* compare rate */ |
588 | res = external_rate(rcs1); |
589 | if (!(flags & AK4114_CHECK_NO_RATE) && runtime && runtime->rate != res) { |
590 | snd_pcm_stream_lock_irqsave(ak4114->capture_substream, _flags); |
591 | if (snd_pcm_running(substream: ak4114->capture_substream)) { |
592 | // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res); |
593 | snd_pcm_stop(substream: ak4114->capture_substream, SNDRV_PCM_STATE_DRAINING); |
594 | res = 1; |
595 | } |
596 | snd_pcm_stream_unlock_irqrestore(substream: ak4114->capture_substream, flags: _flags); |
597 | } |
598 | return res; |
599 | } |
600 | EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors); |
601 | |
602 | static void ak4114_stats(struct work_struct *work) |
603 | { |
604 | struct ak4114 *chip = container_of(work, struct ak4114, work.work); |
605 | |
606 | if (atomic_inc_return(v: &chip->wq_processing) == 1) |
607 | snd_ak4114_check_rate_and_errors(chip, chip->check_flags); |
608 | if (atomic_dec_and_test(v: &chip->wq_processing)) |
609 | schedule_delayed_work(dwork: &chip->work, HZ / 10); |
610 | } |
611 | |
612 | #ifdef CONFIG_PM |
613 | void snd_ak4114_suspend(struct ak4114 *chip) |
614 | { |
615 | atomic_inc(v: &chip->wq_processing); /* don't schedule new work */ |
616 | cancel_delayed_work_sync(dwork: &chip->work); |
617 | } |
618 | EXPORT_SYMBOL(snd_ak4114_suspend); |
619 | |
620 | void snd_ak4114_resume(struct ak4114 *chip) |
621 | { |
622 | atomic_dec(v: &chip->wq_processing); |
623 | snd_ak4114_reinit(chip); |
624 | } |
625 | EXPORT_SYMBOL(snd_ak4114_resume); |
626 | #endif |
627 | |