diff options
author | Pavel Hofman <pavel.hofman@ivitera.com> | 2009-09-16 16:25:37 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-21 09:45:07 -0400 |
commit | 42cfa276aebd28e5cc4350ff6c7d75f1cb84dd98 (patch) | |
tree | 5456711f5170f5b1fec06aef201d01a24ed8777a /sound | |
parent | 8f34692f63d66805b51ff408f4067748d3c1c3fd (diff) |
ALSA: ak4113 support
* complete support for ak4113
* based on code for ak4114 and ak4117
Signed-off-by: Pavel Hofman <pavel.hofman@ivitera.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/i2c/other/Makefile | 3 | ||||
-rw-r--r-- | sound/i2c/other/ak4113.c | 639 |
2 files changed, 641 insertions, 1 deletions
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 703d954238f4..2dad40f3f622 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | snd-ak4114-objs := ak4114.o | 6 | snd-ak4114-objs := ak4114.o |
7 | snd-ak4117-objs := ak4117.o | 7 | snd-ak4117-objs := ak4117.o |
8 | snd-ak4113-objs := ak4113.o | ||
8 | snd-ak4xxx-adda-objs := ak4xxx-adda.o | 9 | snd-ak4xxx-adda-objs := ak4xxx-adda.o |
9 | snd-pt2258-objs := pt2258.o | 10 | snd-pt2258-objs := pt2258.o |
10 | snd-tea575x-tuner-objs := tea575x-tuner.o | 11 | snd-tea575x-tuner-objs := tea575x-tuner.o |
@@ -12,5 +13,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.o | |||
12 | # Module Dependency | 13 | # Module Dependency |
13 | obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o | 14 | obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o |
14 | obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o | 15 | obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o |
15 | obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o | 16 | obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o |
16 | obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o | 17 | obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o |
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c new file mode 100644 index 000000000000..fff62cc8607c --- /dev/null +++ b/sound/i2c/other/ak4113.c | |||
@@ -0,0 +1,639 @@ | |||
1 | /* | ||
2 | * Routines for control of the AK4113 via I2C/4-wire serial interface | ||
3 | * IEC958 (S/PDIF) receiver by Asahi Kasei | ||
4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
5 | * Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.com> | ||
6 | * | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/control.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/ak4113.h> | ||
30 | #include <sound/asoundef.h> | ||
31 | #include <sound/info.h> | ||
32 | |||
33 | MODULE_AUTHOR("Pavel Hofman <pavel.hofman@ivitera.com>"); | ||
34 | MODULE_DESCRIPTION("AK4113 IEC958 (S/PDIF) receiver by Asahi Kasei"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | #define AK4113_ADDR 0x00 /* fixed address */ | ||
38 | |||
39 | static void ak4113_stats(struct work_struct *work); | ||
40 | static void ak4113_init_regs(struct ak4113 *chip); | ||
41 | |||
42 | |||
43 | static void reg_write(struct ak4113 *ak4113, unsigned char reg, | ||
44 | unsigned char val) | ||
45 | { | ||
46 | ak4113->write(ak4113->private_data, reg, val); | ||
47 | if (reg < sizeof(ak4113->regmap)) | ||
48 | ak4113->regmap[reg] = val; | ||
49 | } | ||
50 | |||
51 | static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg) | ||
52 | { | ||
53 | return ak4113->read(ak4113->private_data, reg); | ||
54 | } | ||
55 | |||
56 | static void snd_ak4113_free(struct ak4113 *chip) | ||
57 | { | ||
58 | chip->init = 1; /* don't schedule new work */ | ||
59 | mb(); | ||
60 | cancel_delayed_work(&chip->work); | ||
61 | flush_scheduled_work(); | ||
62 | kfree(chip); | ||
63 | } | ||
64 | |||
65 | static int snd_ak4113_dev_free(struct snd_device *device) | ||
66 | { | ||
67 | struct ak4113 *chip = device->device_data; | ||
68 | snd_ak4113_free(chip); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read, | ||
73 | ak4113_write_t *write, const unsigned char pgm[5], | ||
74 | void *private_data, struct ak4113 **r_ak4113) | ||
75 | { | ||
76 | struct ak4113 *chip; | ||
77 | int err = 0; | ||
78 | unsigned char reg; | ||
79 | static struct snd_device_ops ops = { | ||
80 | .dev_free = snd_ak4113_dev_free, | ||
81 | }; | ||
82 | |||
83 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
84 | if (chip == NULL) | ||
85 | return -ENOMEM; | ||
86 | spin_lock_init(&chip->lock); | ||
87 | chip->card = card; | ||
88 | chip->read = read; | ||
89 | chip->write = write; | ||
90 | chip->private_data = private_data; | ||
91 | INIT_DELAYED_WORK(&chip->work, ak4113_stats); | ||
92 | |||
93 | for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) | ||
94 | chip->regmap[reg] = pgm[reg]; | ||
95 | ak4113_init_regs(chip); | ||
96 | |||
97 | chip->rcs0 = reg_read(chip, AK4113_REG_RCS0) & ~(AK4113_QINT | | ||
98 | AK4113_CINT | AK4113_STC); | ||
99 | chip->rcs1 = reg_read(chip, AK4113_REG_RCS1); | ||
100 | chip->rcs2 = reg_read(chip, AK4113_REG_RCS2); | ||
101 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | ||
102 | if (err < 0) | ||
103 | goto __fail; | ||
104 | |||
105 | if (r_ak4113) | ||
106 | *r_ak4113 = chip; | ||
107 | return 0; | ||
108 | |||
109 | __fail: | ||
110 | snd_ak4113_free(chip); | ||
111 | return err < 0 ? err : -EIO; | ||
112 | } | ||
113 | EXPORT_SYMBOL_GPL(snd_ak4113_create); | ||
114 | |||
115 | void snd_ak4113_reg_write(struct ak4113 *chip, unsigned char reg, | ||
116 | unsigned char mask, unsigned char val) | ||
117 | { | ||
118 | if (reg >= AK4113_WRITABLE_REGS) | ||
119 | return; | ||
120 | reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(snd_ak4113_reg_write); | ||
123 | |||
124 | static void ak4113_init_regs(struct ak4113 *chip) | ||
125 | { | ||
126 | unsigned char old = chip->regmap[AK4113_REG_PWRDN], reg; | ||
127 | |||
128 | /* bring the chip to reset state and powerdown state */ | ||
129 | reg_write(chip, AK4113_REG_PWRDN, old & ~(AK4113_RST|AK4113_PWN)); | ||
130 | udelay(200); | ||
131 | /* release reset, but leave powerdown */ | ||
132 | reg_write(chip, AK4113_REG_PWRDN, (old | AK4113_RST) & ~AK4113_PWN); | ||
133 | udelay(200); | ||
134 | for (reg = 1; reg < AK4113_WRITABLE_REGS; reg++) | ||
135 | reg_write(chip, reg, chip->regmap[reg]); | ||
136 | /* release powerdown, everything is initialized now */ | ||
137 | reg_write(chip, AK4113_REG_PWRDN, old | AK4113_RST | AK4113_PWN); | ||
138 | } | ||
139 | |||
140 | void snd_ak4113_reinit(struct ak4113 *chip) | ||
141 | { | ||
142 | chip->init = 1; | ||
143 | mb(); | ||
144 | flush_scheduled_work(); | ||
145 | ak4113_init_regs(chip); | ||
146 | /* bring up statistics / event queing */ | ||
147 | chip->init = 0; | ||
148 | if (chip->kctls[0]) | ||
149 | schedule_delayed_work(&chip->work, HZ / 10); | ||
150 | } | ||
151 | EXPORT_SYMBOL_GPL(snd_ak4113_reinit); | ||
152 | |||
153 | static unsigned int external_rate(unsigned char rcs1) | ||
154 | { | ||
155 | switch (rcs1 & (AK4113_FS0|AK4113_FS1|AK4113_FS2|AK4113_FS3)) { | ||
156 | case AK4113_FS_8000HZ: | ||
157 | return 8000; | ||
158 | case AK4113_FS_11025HZ: | ||
159 | return 11025; | ||
160 | case AK4113_FS_16000HZ: | ||
161 | return 16000; | ||
162 | case AK4113_FS_22050HZ: | ||
163 | return 22050; | ||
164 | case AK4113_FS_24000HZ: | ||
165 | return 24000; | ||
166 | case AK4113_FS_32000HZ: | ||
167 | return 32000; | ||
168 | case AK4113_FS_44100HZ: | ||
169 | return 44100; | ||
170 | case AK4113_FS_48000HZ: | ||
171 | return 48000; | ||
172 | case AK4113_FS_64000HZ: | ||
173 | return 64000; | ||
174 | case AK4113_FS_88200HZ: | ||
175 | return 88200; | ||
176 | case AK4113_FS_96000HZ: | ||
177 | return 96000; | ||
178 | case AK4113_FS_176400HZ: | ||
179 | return 176400; | ||
180 | case AK4113_FS_192000HZ: | ||
181 | return 192000; | ||
182 | default: | ||
183 | return 0; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static int snd_ak4113_in_error_info(struct snd_kcontrol *kcontrol, | ||
188 | struct snd_ctl_elem_info *uinfo) | ||
189 | { | ||
190 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
191 | uinfo->count = 1; | ||
192 | uinfo->value.integer.min = 0; | ||
193 | uinfo->value.integer.max = LONG_MAX; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol, | ||
198 | struct snd_ctl_elem_value *ucontrol) | ||
199 | { | ||
200 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
201 | long *ptr; | ||
202 | |||
203 | spin_lock_irq(&chip->lock); | ||
204 | ptr = (long *)(((char *)chip) + kcontrol->private_value); | ||
205 | ucontrol->value.integer.value[0] = *ptr; | ||
206 | *ptr = 0; | ||
207 | spin_unlock_irq(&chip->lock); | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | #define snd_ak4113_in_bit_info snd_ctl_boolean_mono_info | ||
212 | |||
213 | static int snd_ak4113_in_bit_get(struct snd_kcontrol *kcontrol, | ||
214 | struct snd_ctl_elem_value *ucontrol) | ||
215 | { | ||
216 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
217 | unsigned char reg = kcontrol->private_value & 0xff; | ||
218 | unsigned char bit = (kcontrol->private_value >> 8) & 0xff; | ||
219 | unsigned char inv = (kcontrol->private_value >> 31) & 1; | ||
220 | |||
221 | ucontrol->value.integer.value[0] = | ||
222 | ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int snd_ak4113_rx_info(struct snd_kcontrol *kcontrol, | ||
227 | struct snd_ctl_elem_info *uinfo) | ||
228 | { | ||
229 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
230 | uinfo->count = 1; | ||
231 | uinfo->value.integer.min = 0; | ||
232 | uinfo->value.integer.max = 5; | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int snd_ak4113_rx_get(struct snd_kcontrol *kcontrol, | ||
237 | struct snd_ctl_elem_value *ucontrol) | ||
238 | { | ||
239 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
240 | |||
241 | ucontrol->value.integer.value[0] = | ||
242 | (AK4113_IPS(chip->regmap[AK4113_REG_IO1])); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol, | ||
247 | struct snd_ctl_elem_value *ucontrol) | ||
248 | { | ||
249 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
250 | int change; | ||
251 | u8 old_val; | ||
252 | |||
253 | spin_lock_irq(&chip->lock); | ||
254 | old_val = chip->regmap[AK4113_REG_IO1]; | ||
255 | change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val); | ||
256 | if (change) | ||
257 | reg_write(chip, AK4113_REG_IO1, | ||
258 | (old_val & (~AK4113_IPS(0xff))) | | ||
259 | (AK4113_IPS(ucontrol->value.integer.value[0]))); | ||
260 | spin_unlock_irq(&chip->lock); | ||
261 | return change; | ||
262 | } | ||
263 | |||
264 | static int snd_ak4113_rate_info(struct snd_kcontrol *kcontrol, | ||
265 | struct snd_ctl_elem_info *uinfo) | ||
266 | { | ||
267 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
268 | uinfo->count = 1; | ||
269 | uinfo->value.integer.min = 0; | ||
270 | uinfo->value.integer.max = 192000; | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int snd_ak4113_rate_get(struct snd_kcontrol *kcontrol, | ||
275 | struct snd_ctl_elem_value *ucontrol) | ||
276 | { | ||
277 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
278 | |||
279 | ucontrol->value.integer.value[0] = external_rate(reg_read(chip, | ||
280 | AK4113_REG_RCS1)); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int snd_ak4113_spdif_info(struct snd_kcontrol *kcontrol, | ||
285 | struct snd_ctl_elem_info *uinfo) | ||
286 | { | ||
287 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
288 | uinfo->count = 1; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int snd_ak4113_spdif_get(struct snd_kcontrol *kcontrol, | ||
293 | struct snd_ctl_elem_value *ucontrol) | ||
294 | { | ||
295 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
296 | unsigned i; | ||
297 | |||
298 | for (i = 0; i < AK4113_REG_RXCSB_SIZE; i++) | ||
299 | ucontrol->value.iec958.status[i] = reg_read(chip, | ||
300 | AK4113_REG_RXCSB0 + i); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static int snd_ak4113_spdif_mask_info(struct snd_kcontrol *kcontrol, | ||
305 | struct snd_ctl_elem_info *uinfo) | ||
306 | { | ||
307 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
308 | uinfo->count = 1; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int snd_ak4113_spdif_mask_get(struct snd_kcontrol *kcontrol, | ||
313 | struct snd_ctl_elem_value *ucontrol) | ||
314 | { | ||
315 | memset(ucontrol->value.iec958.status, 0xff, AK4113_REG_RXCSB_SIZE); | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int snd_ak4113_spdif_pinfo(struct snd_kcontrol *kcontrol, | ||
320 | struct snd_ctl_elem_info *uinfo) | ||
321 | { | ||
322 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
323 | uinfo->value.integer.min = 0; | ||
324 | uinfo->value.integer.max = 0xffff; | ||
325 | uinfo->count = 4; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int snd_ak4113_spdif_pget(struct snd_kcontrol *kcontrol, | ||
330 | struct snd_ctl_elem_value *ucontrol) | ||
331 | { | ||
332 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
333 | unsigned short tmp; | ||
334 | |||
335 | ucontrol->value.integer.value[0] = 0xf8f2; | ||
336 | ucontrol->value.integer.value[1] = 0x4e1f; | ||
337 | tmp = reg_read(chip, AK4113_REG_Pc0) | | ||
338 | (reg_read(chip, AK4113_REG_Pc1) << 8); | ||
339 | ucontrol->value.integer.value[2] = tmp; | ||
340 | tmp = reg_read(chip, AK4113_REG_Pd0) | | ||
341 | (reg_read(chip, AK4113_REG_Pd1) << 8); | ||
342 | ucontrol->value.integer.value[3] = tmp; | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int snd_ak4113_spdif_qinfo(struct snd_kcontrol *kcontrol, | ||
347 | struct snd_ctl_elem_info *uinfo) | ||
348 | { | ||
349 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
350 | uinfo->count = AK4113_REG_QSUB_SIZE; | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int snd_ak4113_spdif_qget(struct snd_kcontrol *kcontrol, | ||
355 | struct snd_ctl_elem_value *ucontrol) | ||
356 | { | ||
357 | struct ak4113 *chip = snd_kcontrol_chip(kcontrol); | ||
358 | unsigned i; | ||
359 | |||
360 | for (i = 0; i < AK4113_REG_QSUB_SIZE; i++) | ||
361 | ucontrol->value.bytes.data[i] = reg_read(chip, | ||
362 | AK4113_REG_QSUB_ADDR + i); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* Don't forget to change AK4113_CONTROLS define!!! */ | ||
367 | static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { | ||
368 | { | ||
369 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
370 | .name = "IEC958 Parity Errors", | ||
371 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
372 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
373 | .info = snd_ak4113_in_error_info, | ||
374 | .get = snd_ak4113_in_error_get, | ||
375 | .private_value = offsetof(struct ak4113, parity_errors), | ||
376 | }, | ||
377 | { | ||
378 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
379 | .name = "IEC958 V-Bit Errors", | ||
380 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
381 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
382 | .info = snd_ak4113_in_error_info, | ||
383 | .get = snd_ak4113_in_error_get, | ||
384 | .private_value = offsetof(struct ak4113, v_bit_errors), | ||
385 | }, | ||
386 | { | ||
387 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
388 | .name = "IEC958 C-CRC Errors", | ||
389 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
390 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
391 | .info = snd_ak4113_in_error_info, | ||
392 | .get = snd_ak4113_in_error_get, | ||
393 | .private_value = offsetof(struct ak4113, ccrc_errors), | ||
394 | }, | ||
395 | { | ||
396 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
397 | .name = "IEC958 Q-CRC Errors", | ||
398 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
399 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
400 | .info = snd_ak4113_in_error_info, | ||
401 | .get = snd_ak4113_in_error_get, | ||
402 | .private_value = offsetof(struct ak4113, qcrc_errors), | ||
403 | }, | ||
404 | { | ||
405 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
406 | .name = "IEC958 External Rate", | ||
407 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
408 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
409 | .info = snd_ak4113_rate_info, | ||
410 | .get = snd_ak4113_rate_get, | ||
411 | }, | ||
412 | { | ||
413 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
414 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), | ||
415 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
416 | .info = snd_ak4113_spdif_mask_info, | ||
417 | .get = snd_ak4113_spdif_mask_get, | ||
418 | }, | ||
419 | { | ||
420 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
421 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
422 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
423 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
424 | .info = snd_ak4113_spdif_info, | ||
425 | .get = snd_ak4113_spdif_get, | ||
426 | }, | ||
427 | { | ||
428 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
429 | .name = "IEC958 Preample Capture Default", | ||
430 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
431 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
432 | .info = snd_ak4113_spdif_pinfo, | ||
433 | .get = snd_ak4113_spdif_pget, | ||
434 | }, | ||
435 | { | ||
436 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
437 | .name = "IEC958 Q-subcode Capture Default", | ||
438 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
439 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
440 | .info = snd_ak4113_spdif_qinfo, | ||
441 | .get = snd_ak4113_spdif_qget, | ||
442 | }, | ||
443 | { | ||
444 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
445 | .name = "IEC958 Audio", | ||
446 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
447 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
448 | .info = snd_ak4113_in_bit_info, | ||
449 | .get = snd_ak4113_in_bit_get, | ||
450 | .private_value = (1<<31) | (1<<8) | AK4113_REG_RCS0, | ||
451 | }, | ||
452 | { | ||
453 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
454 | .name = "IEC958 Non-PCM Bitstream", | ||
455 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
456 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
457 | .info = snd_ak4113_in_bit_info, | ||
458 | .get = snd_ak4113_in_bit_get, | ||
459 | .private_value = (0<<8) | AK4113_REG_RCS1, | ||
460 | }, | ||
461 | { | ||
462 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
463 | .name = "IEC958 DTS Bitstream", | ||
464 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
465 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
466 | .info = snd_ak4113_in_bit_info, | ||
467 | .get = snd_ak4113_in_bit_get, | ||
468 | .private_value = (1<<8) | AK4113_REG_RCS1, | ||
469 | }, | ||
470 | { | ||
471 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
472 | .name = "AK4113 Input Select", | ||
473 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
474 | SNDRV_CTL_ELEM_ACCESS_WRITE, | ||
475 | .info = snd_ak4113_rx_info, | ||
476 | .get = snd_ak4113_rx_get, | ||
477 | .put = snd_ak4113_rx_put, | ||
478 | } | ||
479 | }; | ||
480 | |||
481 | static void snd_ak4113_proc_regs_read(struct snd_info_entry *entry, | ||
482 | struct snd_info_buffer *buffer) | ||
483 | { | ||
484 | struct ak4113 *ak4113 = entry->private_data; | ||
485 | int reg, val; | ||
486 | /* all ak4113 registers 0x00 - 0x1c */ | ||
487 | for (reg = 0; reg < 0x1d; reg++) { | ||
488 | val = reg_read(ak4113, reg); | ||
489 | snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | static void snd_ak4113_proc_init(struct ak4113 *ak4113) | ||
494 | { | ||
495 | struct snd_info_entry *entry; | ||
496 | if (!snd_card_proc_new(ak4113->card, "ak4113", &entry)) | ||
497 | snd_info_set_text_ops(entry, ak4113, snd_ak4113_proc_regs_read); | ||
498 | } | ||
499 | |||
500 | int snd_ak4113_build(struct ak4113 *ak4113, | ||
501 | struct snd_pcm_substream *cap_substream) | ||
502 | { | ||
503 | struct snd_kcontrol *kctl; | ||
504 | unsigned int idx; | ||
505 | int err; | ||
506 | |||
507 | if (snd_BUG_ON(!cap_substream)) | ||
508 | return -EINVAL; | ||
509 | ak4113->substream = cap_substream; | ||
510 | for (idx = 0; idx < AK4113_CONTROLS; idx++) { | ||
511 | kctl = snd_ctl_new1(&snd_ak4113_iec958_controls[idx], ak4113); | ||
512 | if (kctl == NULL) | ||
513 | return -ENOMEM; | ||
514 | kctl->id.device = cap_substream->pcm->device; | ||
515 | kctl->id.subdevice = cap_substream->number; | ||
516 | err = snd_ctl_add(ak4113->card, kctl); | ||
517 | if (err < 0) | ||
518 | return err; | ||
519 | ak4113->kctls[idx] = kctl; | ||
520 | } | ||
521 | snd_ak4113_proc_init(ak4113); | ||
522 | /* trigger workq */ | ||
523 | schedule_delayed_work(&ak4113->work, HZ / 10); | ||
524 | return 0; | ||
525 | } | ||
526 | EXPORT_SYMBOL_GPL(snd_ak4113_build); | ||
527 | |||
528 | int snd_ak4113_external_rate(struct ak4113 *ak4113) | ||
529 | { | ||
530 | unsigned char rcs1; | ||
531 | |||
532 | rcs1 = reg_read(ak4113, AK4113_REG_RCS1); | ||
533 | return external_rate(rcs1); | ||
534 | } | ||
535 | EXPORT_SYMBOL_GPL(snd_ak4113_external_rate); | ||
536 | |||
537 | int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags) | ||
538 | { | ||
539 | struct snd_pcm_runtime *runtime = | ||
540 | ak4113->substream ? ak4113->substream->runtime : NULL; | ||
541 | unsigned long _flags; | ||
542 | int res = 0; | ||
543 | unsigned char rcs0, rcs1, rcs2; | ||
544 | unsigned char c0, c1; | ||
545 | |||
546 | rcs1 = reg_read(ak4113, AK4113_REG_RCS1); | ||
547 | if (flags & AK4113_CHECK_NO_STAT) | ||
548 | goto __rate; | ||
549 | rcs0 = reg_read(ak4113, AK4113_REG_RCS0); | ||
550 | rcs2 = reg_read(ak4113, AK4113_REG_RCS2); | ||
551 | spin_lock_irqsave(&ak4113->lock, _flags); | ||
552 | if (rcs0 & AK4113_PAR) | ||
553 | ak4113->parity_errors++; | ||
554 | if (rcs0 & AK4113_V) | ||
555 | ak4113->v_bit_errors++; | ||
556 | if (rcs2 & AK4113_CCRC) | ||
557 | ak4113->ccrc_errors++; | ||
558 | if (rcs2 & AK4113_QCRC) | ||
559 | ak4113->qcrc_errors++; | ||
560 | c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | | ||
561 | AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^ | ||
562 | (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | | ||
563 | AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)); | ||
564 | c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | | ||
565 | AK4113_DAT | 0xf0)) ^ | ||
566 | (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | | ||
567 | AK4113_DAT | 0xf0)); | ||
568 | ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC); | ||
569 | ak4113->rcs1 = rcs1; | ||
570 | ak4113->rcs2 = rcs2; | ||
571 | spin_unlock_irqrestore(&ak4113->lock, _flags); | ||
572 | |||
573 | if (rcs0 & AK4113_PAR) | ||
574 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
575 | &ak4113->kctls[0]->id); | ||
576 | if (rcs0 & AK4113_V) | ||
577 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
578 | &ak4113->kctls[1]->id); | ||
579 | if (rcs2 & AK4113_CCRC) | ||
580 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
581 | &ak4113->kctls[2]->id); | ||
582 | if (rcs2 & AK4113_QCRC) | ||
583 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
584 | &ak4113->kctls[3]->id); | ||
585 | |||
586 | /* rate change */ | ||
587 | if (c1 & 0xf0) | ||
588 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
589 | &ak4113->kctls[4]->id); | ||
590 | |||
591 | if ((c1 & AK4113_PEM) | (c0 & AK4113_CINT)) | ||
592 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
593 | &ak4113->kctls[6]->id); | ||
594 | if (c0 & AK4113_QINT) | ||
595 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
596 | &ak4113->kctls[8]->id); | ||
597 | |||
598 | if (c0 & AK4113_AUDION) | ||
599 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
600 | &ak4113->kctls[9]->id); | ||
601 | if (c1 & AK4113_NPCM) | ||
602 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
603 | &ak4113->kctls[10]->id); | ||
604 | if (c1 & AK4113_DTSCD) | ||
605 | snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
606 | &ak4113->kctls[11]->id); | ||
607 | |||
608 | if (ak4113->change_callback && (c0 | c1) != 0) | ||
609 | ak4113->change_callback(ak4113, c0, c1); | ||
610 | |||
611 | __rate: | ||
612 | /* compare rate */ | ||
613 | res = external_rate(rcs1); | ||
614 | if (!(flags & AK4113_CHECK_NO_RATE) && runtime && | ||
615 | (runtime->rate != res)) { | ||
616 | snd_pcm_stream_lock_irqsave(ak4113->substream, _flags); | ||
617 | if (snd_pcm_running(ak4113->substream)) { | ||
618 | /*printk(KERN_DEBUG "rate changed (%i <- %i)\n", | ||
619 | * runtime->rate, res); */ | ||
620 | snd_pcm_stop(ak4113->substream, | ||
621 | SNDRV_PCM_STATE_DRAINING); | ||
622 | wake_up(&runtime->sleep); | ||
623 | res = 1; | ||
624 | } | ||
625 | snd_pcm_stream_unlock_irqrestore(ak4113->substream, _flags); | ||
626 | } | ||
627 | return res; | ||
628 | } | ||
629 | EXPORT_SYMBOL_GPL(snd_ak4113_check_rate_and_errors); | ||
630 | |||
631 | static void ak4113_stats(struct work_struct *work) | ||
632 | { | ||
633 | struct ak4113 *chip = container_of(work, struct ak4113, work.work); | ||
634 | |||
635 | if (!chip->init) | ||
636 | snd_ak4113_check_rate_and_errors(chip, chip->check_flags); | ||
637 | |||
638 | schedule_delayed_work(&chip->work, HZ / 10); | ||
639 | } | ||