Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/i2c/other/ak4117.c
29278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Routines for control of the AK4117 via 4-wire serial interface
4
* IEC958 (S/PDIF) receiver by Asahi Kasei
5
* Copyright (c) by Jaroslav Kysela <[email protected]>
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/ak4117.h>
15
#include <sound/asoundef.h>
16
17
MODULE_AUTHOR("Jaroslav Kysela <[email protected]>");
18
MODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei");
19
MODULE_LICENSE("GPL");
20
21
#define AK4117_ADDR 0x00 /* fixed address */
22
23
static void snd_ak4117_timer(struct timer_list *t);
24
25
static void reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char val)
26
{
27
ak4117->write(ak4117->private_data, reg, val);
28
if (reg < sizeof(ak4117->regmap))
29
ak4117->regmap[reg] = val;
30
}
31
32
static inline unsigned char reg_read(struct ak4117 *ak4117, unsigned char reg)
33
{
34
return ak4117->read(ak4117->private_data, reg);
35
}
36
37
static void snd_ak4117_free(struct ak4117 *chip)
38
{
39
timer_shutdown_sync(&chip->timer);
40
kfree(chip);
41
}
42
43
static int snd_ak4117_dev_free(struct snd_device *device)
44
{
45
struct ak4117 *chip = device->device_data;
46
snd_ak4117_free(chip);
47
return 0;
48
}
49
50
int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
51
const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
52
{
53
struct ak4117 *chip;
54
int err = 0;
55
unsigned char reg;
56
static const struct snd_device_ops ops = {
57
.dev_free = snd_ak4117_dev_free,
58
};
59
60
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
61
if (chip == NULL)
62
return -ENOMEM;
63
spin_lock_init(&chip->lock);
64
chip->card = card;
65
chip->read = read;
66
chip->write = write;
67
chip->private_data = private_data;
68
timer_setup(&chip->timer, snd_ak4117_timer, 0);
69
70
for (reg = 0; reg < 5; reg++)
71
chip->regmap[reg] = pgm[reg];
72
snd_ak4117_reinit(chip);
73
74
chip->rcs0 = reg_read(chip, AK4117_REG_RCS0) & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
75
chip->rcs1 = reg_read(chip, AK4117_REG_RCS1);
76
chip->rcs2 = reg_read(chip, AK4117_REG_RCS2);
77
78
err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops);
79
if (err < 0)
80
goto __fail;
81
82
if (r_ak4117)
83
*r_ak4117 = chip;
84
return 0;
85
86
__fail:
87
snd_ak4117_free(chip);
88
return err;
89
}
90
91
void snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val)
92
{
93
if (reg >= 5)
94
return;
95
reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
96
}
97
98
void snd_ak4117_reinit(struct ak4117 *chip)
99
{
100
unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg;
101
102
timer_delete(&chip->timer);
103
chip->init = 1;
104
/* bring the chip to reset state and powerdown state */
105
reg_write(chip, AK4117_REG_PWRDN, 0);
106
udelay(200);
107
/* release reset, but leave powerdown */
108
reg_write(chip, AK4117_REG_PWRDN, (old | AK4117_RST) & ~AK4117_PWN);
109
udelay(200);
110
for (reg = 1; reg < 5; reg++)
111
reg_write(chip, reg, chip->regmap[reg]);
112
/* release powerdown, everything is initialized now */
113
reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN);
114
chip->init = 0;
115
mod_timer(&chip->timer, 1 + jiffies);
116
}
117
118
static unsigned int external_rate(unsigned char rcs1)
119
{
120
switch (rcs1 & (AK4117_FS0|AK4117_FS1|AK4117_FS2|AK4117_FS3)) {
121
case AK4117_FS_32000HZ: return 32000;
122
case AK4117_FS_44100HZ: return 44100;
123
case AK4117_FS_48000HZ: return 48000;
124
case AK4117_FS_88200HZ: return 88200;
125
case AK4117_FS_96000HZ: return 96000;
126
case AK4117_FS_176400HZ: return 176400;
127
case AK4117_FS_192000HZ: return 192000;
128
default: return 0;
129
}
130
}
131
132
static int snd_ak4117_in_error_info(struct snd_kcontrol *kcontrol,
133
struct snd_ctl_elem_info *uinfo)
134
{
135
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
136
uinfo->count = 1;
137
uinfo->value.integer.min = 0;
138
uinfo->value.integer.max = LONG_MAX;
139
return 0;
140
}
141
142
static int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol,
143
struct snd_ctl_elem_value *ucontrol)
144
{
145
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
146
147
guard(spinlock_irq)(&chip->lock);
148
ucontrol->value.integer.value[0] =
149
chip->errors[kcontrol->private_value];
150
chip->errors[kcontrol->private_value] = 0;
151
return 0;
152
}
153
154
#define snd_ak4117_in_bit_info snd_ctl_boolean_mono_info
155
156
static int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol,
157
struct snd_ctl_elem_value *ucontrol)
158
{
159
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
160
unsigned char reg = kcontrol->private_value & 0xff;
161
unsigned char bit = (kcontrol->private_value >> 8) & 0xff;
162
unsigned char inv = (kcontrol->private_value >> 31) & 1;
163
164
ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;
165
return 0;
166
}
167
168
static int snd_ak4117_rx_info(struct snd_kcontrol *kcontrol,
169
struct snd_ctl_elem_info *uinfo)
170
{
171
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
172
uinfo->count = 1;
173
uinfo->value.integer.min = 0;
174
uinfo->value.integer.max = 1;
175
return 0;
176
}
177
178
static int snd_ak4117_rx_get(struct snd_kcontrol *kcontrol,
179
struct snd_ctl_elem_value *ucontrol)
180
{
181
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
182
183
ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0;
184
return 0;
185
}
186
187
static int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol,
188
struct snd_ctl_elem_value *ucontrol)
189
{
190
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
191
int change;
192
u8 old_val;
193
194
guard(spinlock_irq)(&chip->lock);
195
old_val = chip->regmap[AK4117_REG_IO];
196
change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0);
197
if (change)
198
reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0));
199
return change;
200
}
201
202
static int snd_ak4117_rate_info(struct snd_kcontrol *kcontrol,
203
struct snd_ctl_elem_info *uinfo)
204
{
205
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
206
uinfo->count = 1;
207
uinfo->value.integer.min = 0;
208
uinfo->value.integer.max = 192000;
209
return 0;
210
}
211
212
static int snd_ak4117_rate_get(struct snd_kcontrol *kcontrol,
213
struct snd_ctl_elem_value *ucontrol)
214
{
215
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
216
217
ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1));
218
return 0;
219
}
220
221
static int snd_ak4117_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
222
{
223
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
224
uinfo->count = 1;
225
return 0;
226
}
227
228
static int snd_ak4117_spdif_get(struct snd_kcontrol *kcontrol,
229
struct snd_ctl_elem_value *ucontrol)
230
{
231
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
232
unsigned i;
233
234
for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++)
235
ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i);
236
return 0;
237
}
238
239
static int snd_ak4117_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
240
{
241
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
242
uinfo->count = 1;
243
return 0;
244
}
245
246
static int snd_ak4117_spdif_mask_get(struct snd_kcontrol *kcontrol,
247
struct snd_ctl_elem_value *ucontrol)
248
{
249
memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE);
250
return 0;
251
}
252
253
static int snd_ak4117_spdif_pinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
254
{
255
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
256
uinfo->value.integer.min = 0;
257
uinfo->value.integer.max = 0xffff;
258
uinfo->count = 4;
259
return 0;
260
}
261
262
static int snd_ak4117_spdif_pget(struct snd_kcontrol *kcontrol,
263
struct snd_ctl_elem_value *ucontrol)
264
{
265
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
266
unsigned short tmp;
267
268
ucontrol->value.integer.value[0] = 0xf8f2;
269
ucontrol->value.integer.value[1] = 0x4e1f;
270
tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8);
271
ucontrol->value.integer.value[2] = tmp;
272
tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8);
273
ucontrol->value.integer.value[3] = tmp;
274
return 0;
275
}
276
277
static int snd_ak4117_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
278
{
279
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
280
uinfo->count = AK4117_REG_QSUB_SIZE;
281
return 0;
282
}
283
284
static int snd_ak4117_spdif_qget(struct snd_kcontrol *kcontrol,
285
struct snd_ctl_elem_value *ucontrol)
286
{
287
struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
288
unsigned i;
289
290
for (i = 0; i < AK4117_REG_QSUB_SIZE; i++)
291
ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i);
292
return 0;
293
}
294
295
/* Don't forget to change AK4117_CONTROLS define!!! */
296
static const struct snd_kcontrol_new snd_ak4117_iec958_controls[] = {
297
{
298
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
299
.name = "IEC958 Parity Errors",
300
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
301
.info = snd_ak4117_in_error_info,
302
.get = snd_ak4117_in_error_get,
303
.private_value = AK4117_PARITY_ERRORS,
304
},
305
{
306
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
307
.name = "IEC958 V-Bit Errors",
308
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
309
.info = snd_ak4117_in_error_info,
310
.get = snd_ak4117_in_error_get,
311
.private_value = AK4117_V_BIT_ERRORS,
312
},
313
{
314
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
315
.name = "IEC958 C-CRC Errors",
316
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
317
.info = snd_ak4117_in_error_info,
318
.get = snd_ak4117_in_error_get,
319
.private_value = AK4117_CCRC_ERRORS,
320
},
321
{
322
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
323
.name = "IEC958 Q-CRC Errors",
324
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
325
.info = snd_ak4117_in_error_info,
326
.get = snd_ak4117_in_error_get,
327
.private_value = AK4117_QCRC_ERRORS,
328
},
329
{
330
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
331
.name = "IEC958 External Rate",
332
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
333
.info = snd_ak4117_rate_info,
334
.get = snd_ak4117_rate_get,
335
},
336
{
337
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
338
.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
339
.access = SNDRV_CTL_ELEM_ACCESS_READ,
340
.info = snd_ak4117_spdif_mask_info,
341
.get = snd_ak4117_spdif_mask_get,
342
},
343
{
344
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
345
.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
346
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
347
.info = snd_ak4117_spdif_info,
348
.get = snd_ak4117_spdif_get,
349
},
350
{
351
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
352
.name = "IEC958 Preamble Capture Default",
353
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
354
.info = snd_ak4117_spdif_pinfo,
355
.get = snd_ak4117_spdif_pget,
356
},
357
{
358
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
359
.name = "IEC958 Q-subcode Capture Default",
360
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
361
.info = snd_ak4117_spdif_qinfo,
362
.get = snd_ak4117_spdif_qget,
363
},
364
{
365
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
366
.name = "IEC958 Audio",
367
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
368
.info = snd_ak4117_in_bit_info,
369
.get = snd_ak4117_in_bit_get,
370
.private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0,
371
},
372
{
373
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
374
.name = "IEC958 Non-PCM Bitstream",
375
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
376
.info = snd_ak4117_in_bit_info,
377
.get = snd_ak4117_in_bit_get,
378
.private_value = (5<<8) | AK4117_REG_RCS1,
379
},
380
{
381
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
382
.name = "IEC958 DTS Bitstream",
383
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
384
.info = snd_ak4117_in_bit_info,
385
.get = snd_ak4117_in_bit_get,
386
.private_value = (6<<8) | AK4117_REG_RCS1,
387
},
388
{
389
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
390
.name = "AK4117 Input Select",
391
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
392
.info = snd_ak4117_rx_info,
393
.get = snd_ak4117_rx_get,
394
.put = snd_ak4117_rx_put,
395
}
396
};
397
398
int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *cap_substream)
399
{
400
struct snd_kcontrol *kctl;
401
unsigned int idx;
402
int err;
403
404
if (snd_BUG_ON(!cap_substream))
405
return -EINVAL;
406
ak4117->substream = cap_substream;
407
for (idx = 0; idx < AK4117_CONTROLS; idx++) {
408
kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117);
409
if (kctl == NULL)
410
return -ENOMEM;
411
kctl->id.device = cap_substream->pcm->device;
412
kctl->id.subdevice = cap_substream->number;
413
err = snd_ctl_add(ak4117->card, kctl);
414
if (err < 0)
415
return err;
416
ak4117->kctls[idx] = kctl;
417
}
418
return 0;
419
}
420
421
int snd_ak4117_external_rate(struct ak4117 *ak4117)
422
{
423
unsigned char rcs1;
424
425
rcs1 = reg_read(ak4117, AK4117_REG_RCS1);
426
return external_rate(rcs1);
427
}
428
429
int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags)
430
{
431
struct snd_pcm_runtime *runtime = ak4117->substream ? ak4117->substream->runtime : NULL;
432
unsigned long _flags;
433
int res = 0;
434
unsigned char rcs0, rcs1, rcs2;
435
unsigned char c0, c1;
436
437
rcs1 = reg_read(ak4117, AK4117_REG_RCS1);
438
if (flags & AK4117_CHECK_NO_STAT)
439
goto __rate;
440
rcs0 = reg_read(ak4117, AK4117_REG_RCS0);
441
rcs2 = reg_read(ak4117, AK4117_REG_RCS2);
442
scoped_guard(spinlock_irqsave, &ak4117->lock) {
443
if (rcs0 & AK4117_PAR)
444
ak4117->errors[AK4117_PARITY_ERRORS]++;
445
if (rcs0 & AK4117_V)
446
ak4117->errors[AK4117_V_BIT_ERRORS]++;
447
if (rcs2 & AK4117_CCRC)
448
ak4117->errors[AK4117_CCRC_ERRORS]++;
449
if (rcs2 & AK4117_QCRC)
450
ak4117->errors[AK4117_QCRC_ERRORS]++;
451
c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^
452
(rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK));
453
c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^
454
(rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f));
455
ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
456
ak4117->rcs1 = rcs1;
457
ak4117->rcs2 = rcs2;
458
}
459
460
if (rcs0 & AK4117_PAR)
461
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id);
462
if (rcs0 & AK4117_V)
463
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id);
464
if (rcs2 & AK4117_CCRC)
465
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id);
466
if (rcs2 & AK4117_QCRC)
467
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id);
468
469
/* rate change */
470
if (c1 & 0x0f)
471
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id);
472
473
if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT))
474
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id);
475
if (c0 & AK4117_QINT)
476
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id);
477
478
if (c0 & AK4117_AUDION)
479
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id);
480
if (c1 & AK4117_NPCM)
481
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id);
482
if (c1 & AK4117_DTSCD)
483
snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id);
484
485
if (ak4117->change_callback && (c0 | c1) != 0)
486
ak4117->change_callback(ak4117, c0, c1);
487
488
__rate:
489
/* compare rate */
490
res = external_rate(rcs1);
491
if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) {
492
snd_pcm_stream_lock_irqsave(ak4117->substream, _flags);
493
if (snd_pcm_running(ak4117->substream)) {
494
snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING);
495
wake_up(&runtime->sleep);
496
res = 1;
497
}
498
snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags);
499
}
500
return res;
501
}
502
503
static void snd_ak4117_timer(struct timer_list *t)
504
{
505
struct ak4117 *chip = timer_container_of(chip, t, timer);
506
507
if (chip->init)
508
return;
509
snd_ak4117_check_rate_and_errors(chip, 0);
510
mod_timer(&chip->timer, 1 + jiffies);
511
}
512
513
EXPORT_SYMBOL(snd_ak4117_create);
514
EXPORT_SYMBOL(snd_ak4117_reg_write);
515
EXPORT_SYMBOL(snd_ak4117_reinit);
516
EXPORT_SYMBOL(snd_ak4117_build);
517
EXPORT_SYMBOL(snd_ak4117_external_rate);
518
EXPORT_SYMBOL(snd_ak4117_check_rate_and_errors);
519
520