ak4117.c 15.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4
/*
 *  Routines for control of the AK4117 via 4-wire serial interface
 *  IEC958 (S/PDIF) receiver by Asahi Kasei
5
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds's avatar
Linus Torvalds committed
6 7 8 9
 */

#include <linux/slab.h>
#include <linux/delay.h>
10
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
11 12 13 14 15 16
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/ak4117.h>
#include <sound/asoundef.h>

17
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
Linus Torvalds's avatar
Linus Torvalds committed
18 19 20 21 22
MODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei");
MODULE_LICENSE("GPL");

#define AK4117_ADDR			0x00 /* fixed address */

23
static void snd_ak4117_timer(struct timer_list *t);
Linus Torvalds's avatar
Linus Torvalds committed
24

25
static void reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char val)
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28 29 30 31
{
	ak4117->write(ak4117->private_data, reg, val);
	if (reg < sizeof(ak4117->regmap))
		ak4117->regmap[reg] = val;
}

32
static inline unsigned char reg_read(struct ak4117 *ak4117, unsigned char reg)
Linus Torvalds's avatar
Linus Torvalds committed
33 34 35 36 37
{
	return ak4117->read(ak4117->private_data, reg);
}

#if 0
38
static void reg_dump(struct ak4117 *ak4117)
Linus Torvalds's avatar
Linus Torvalds committed
39 40 41
{
	int i;

42
	printk(KERN_DEBUG "AK4117 REG DUMP:\n");
Linus Torvalds's avatar
Linus Torvalds committed
43
	for (i = 0; i < 0x1b; i++)
44
		printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0);
Linus Torvalds's avatar
Linus Torvalds committed
45 46 47
}
#endif

48
static void snd_ak4117_free(struct ak4117 *chip)
Linus Torvalds's avatar
Linus Torvalds committed
49
{
50
	del_timer_sync(&chip->timer);
Linus Torvalds's avatar
Linus Torvalds committed
51 52 53
	kfree(chip);
}

54
static int snd_ak4117_dev_free(struct snd_device *device)
Linus Torvalds's avatar
Linus Torvalds committed
55
{
56
	struct ak4117 *chip = device->device_data;
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59 60
	snd_ak4117_free(chip);
	return 0;
}

61
int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
62
		      const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
Linus Torvalds's avatar
Linus Torvalds committed
63
{
64
	struct ak4117 *chip;
Linus Torvalds's avatar
Linus Torvalds committed
65 66
	int err = 0;
	unsigned char reg;
67
	static const struct snd_device_ops ops = {
Linus Torvalds's avatar
Linus Torvalds committed
68 69 70
		.dev_free =     snd_ak4117_dev_free,
	};

71
	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
72 73 74 75 76 77 78
	if (chip == NULL)
		return -ENOMEM;
	spin_lock_init(&chip->lock);
	chip->card = card;
	chip->read = read;
	chip->write = write;
	chip->private_data = private_data;
79
	timer_setup(&chip->timer, snd_ak4117_timer, 0);
Linus Torvalds's avatar
Linus Torvalds committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

	for (reg = 0; reg < 5; reg++)
		chip->regmap[reg] = pgm[reg];
	snd_ak4117_reinit(chip);

	chip->rcs0 = reg_read(chip, AK4117_REG_RCS0) & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
	chip->rcs1 = reg_read(chip, AK4117_REG_RCS1);
	chip->rcs2 = reg_read(chip, AK4117_REG_RCS2);

	if ((err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops)) < 0)
		goto __fail;

	if (r_ak4117)
		*r_ak4117 = chip;
	return 0;

      __fail:
	snd_ak4117_free(chip);
98
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
99 100
}

101
void snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val)
Linus Torvalds's avatar
Linus Torvalds committed
102 103 104 105 106 107
{
	if (reg >= 5)
		return;
	reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
}

108
void snd_ak4117_reinit(struct ak4117 *chip)
Linus Torvalds's avatar
Linus Torvalds committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
{
	unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg;

	del_timer(&chip->timer);
	chip->init = 1;
	/* bring the chip to reset state and powerdown state */
	reg_write(chip, AK4117_REG_PWRDN, 0);
	udelay(200);
	/* release reset, but leave powerdown */
	reg_write(chip, AK4117_REG_PWRDN, (old | AK4117_RST) & ~AK4117_PWN);
	udelay(200);
	for (reg = 1; reg < 5; reg++)
		reg_write(chip, reg, chip->regmap[reg]);
	/* release powerdown, everything is initialized now */
	reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN);
	chip->init = 0;
125
	mod_timer(&chip->timer, 1 + jiffies);
Linus Torvalds's avatar
Linus Torvalds committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
}

static unsigned int external_rate(unsigned char rcs1)
{
	switch (rcs1 & (AK4117_FS0|AK4117_FS1|AK4117_FS2|AK4117_FS3)) {
	case AK4117_FS_32000HZ: return 32000;
	case AK4117_FS_44100HZ: return 44100;
	case AK4117_FS_48000HZ: return 48000;
	case AK4117_FS_88200HZ: return 88200;
	case AK4117_FS_96000HZ: return 96000;
	case AK4117_FS_176400HZ: return 176400;
	case AK4117_FS_192000HZ: return 192000;
	default:		return 0;
	}
}

142 143
static int snd_ak4117_in_error_info(struct snd_kcontrol *kcontrol,
				    struct snd_ctl_elem_info *uinfo)
Linus Torvalds's avatar
Linus Torvalds committed
144 145 146 147 148 149 150 151
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->count = 1;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = LONG_MAX;
	return 0;
}

152 153
static int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
154
{
155
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
156 157

	spin_lock_irq(&chip->lock);
158 159 160
	ucontrol->value.integer.value[0] =
		       chip->errors[kcontrol->private_value];
	chip->errors[kcontrol->private_value] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
161 162 163 164
	spin_unlock_irq(&chip->lock);
	return 0;
}

165
#define snd_ak4117_in_bit_info		snd_ctl_boolean_mono_info
Linus Torvalds's avatar
Linus Torvalds committed
166

167 168
static int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
169
{
170
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
171 172 173 174 175 176 177 178
	unsigned char reg = kcontrol->private_value & 0xff;
	unsigned char bit = (kcontrol->private_value >> 8) & 0xff;
	unsigned char inv = (kcontrol->private_value >> 31) & 1;

	ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;
	return 0;
}

179 180
static int snd_ak4117_rx_info(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_info *uinfo)
Linus Torvalds's avatar
Linus Torvalds committed
181 182 183 184 185 186 187 188
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->count = 1;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = 1;
	return 0;
}

189 190
static int snd_ak4117_rx_get(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
191
{
192
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
193 194 195 196 197

	ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0;
	return 0;
}

198 199
static int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
200
{
201
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
202 203 204 205 206 207 208 209 210 211 212 213
	int change;
	u8 old_val;
	
	spin_lock_irq(&chip->lock);
	old_val = chip->regmap[AK4117_REG_IO];
	change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0);
	if (change)
		reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0));
	spin_unlock_irq(&chip->lock);
	return change;
}

214 215
static int snd_ak4117_rate_info(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_info *uinfo)
Linus Torvalds's avatar
Linus Torvalds committed
216 217 218 219 220 221 222 223
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->count = 1;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = 192000;
	return 0;
}

224 225
static int snd_ak4117_rate_get(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
226
{
227
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
228 229 230 231 232

	ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1));
	return 0;
}

233
static int snd_ak4117_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds's avatar
Linus Torvalds committed
234 235 236 237 238 239
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
	uinfo->count = 1;
	return 0;
}

240 241
static int snd_ak4117_spdif_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
242
{
243
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
244 245 246 247 248 249 250
	unsigned i;

	for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++)
		ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i);
	return 0;
}

251
static int snd_ak4117_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds's avatar
Linus Torvalds committed
252 253 254 255 256 257
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
	uinfo->count = 1;
	return 0;
}

258 259
static int snd_ak4117_spdif_mask_get(struct snd_kcontrol *kcontrol,
				      struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
260 261 262 263 264
{
	memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE);
	return 0;
}

265
static int snd_ak4117_spdif_pinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds's avatar
Linus Torvalds committed
266 267 268 269 270 271 272 273
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = 0xffff;
	uinfo->count = 4;
	return 0;
}

274 275
static int snd_ak4117_spdif_pget(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
276
{
277
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
278 279 280 281 282 283 284 285 286 287 288
	unsigned short tmp;

	ucontrol->value.integer.value[0] = 0xf8f2;
	ucontrol->value.integer.value[1] = 0x4e1f;
	tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8);
	ucontrol->value.integer.value[2] = tmp;
	tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8);
	ucontrol->value.integer.value[3] = tmp;
	return 0;
}

289
static int snd_ak4117_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds's avatar
Linus Torvalds committed
290 291 292 293 294 295
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
	uinfo->count = AK4117_REG_QSUB_SIZE;
	return 0;
}

296 297
static int snd_ak4117_spdif_qget(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds's avatar
Linus Torvalds committed
298
{
299
	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);
Linus Torvalds's avatar
Linus Torvalds committed
300 301 302 303 304 305 306 307
	unsigned i;

	for (i = 0; i < AK4117_REG_QSUB_SIZE; i++)
		ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i);
	return 0;
}

/* Don't forget to change AK4117_CONTROLS define!!! */
308
static const struct snd_kcontrol_new snd_ak4117_iec958_controls[] = {
Linus Torvalds's avatar
Linus Torvalds committed
309 310 311 312 313 314
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 Parity Errors",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_in_error_info,
	.get =		snd_ak4117_in_error_get,
315
	.private_value = AK4117_PARITY_ERRORS,
Linus Torvalds's avatar
Linus Torvalds committed
316 317 318 319 320 321 322
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 V-Bit Errors",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_in_error_info,
	.get =		snd_ak4117_in_error_get,
323
	.private_value = AK4117_V_BIT_ERRORS,
Linus Torvalds's avatar
Linus Torvalds committed
324 325 326 327 328 329 330
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 C-CRC Errors",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_in_error_info,
	.get =		snd_ak4117_in_error_get,
331
	.private_value = AK4117_CCRC_ERRORS,
Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335 336 337 338
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 Q-CRC Errors",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_in_error_info,
	.get =		snd_ak4117_in_error_get,
339
	.private_value = AK4117_QCRC_ERRORS,
Linus Torvalds's avatar
Linus Torvalds committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 External Rate",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_rate_info,
	.get =		snd_ak4117_rate_get,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
	.info =		snd_ak4117_spdif_mask_info,
	.get =		snd_ak4117_spdif_mask_get,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_spdif_info,
	.get =		snd_ak4117_spdif_get,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
364
	.name =		"IEC958 Preamble Capture Default",
Linus Torvalds's avatar
Linus Torvalds committed
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_spdif_pinfo,
	.get =		snd_ak4117_spdif_pget,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 Q-subcode Capture Default",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_spdif_qinfo,
	.get =		snd_ak4117_spdif_qget,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 Audio",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_in_bit_info,
	.get =		snd_ak4117_in_bit_get,
	.private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 Non-PCM Bitstream",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_in_bit_info,
	.get =		snd_ak4117_in_bit_get,
	.private_value = (5<<8) | AK4117_REG_RCS1,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"IEC958 DTS Bitstream",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
	.info =		snd_ak4117_in_bit_info,
	.get =		snd_ak4117_in_bit_get,
	.private_value = (6<<8) | AK4117_REG_RCS1,
},
{
	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
	.name =		"AK4117 Input Select",
	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
	.info =		snd_ak4117_rx_info,
	.get =		snd_ak4117_rx_get,
	.put =		snd_ak4117_rx_put,
}
};

410
int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *cap_substream)
Linus Torvalds's avatar
Linus Torvalds committed
411
{
412
	struct snd_kcontrol *kctl;
Linus Torvalds's avatar
Linus Torvalds committed
413 414 415
	unsigned int idx;
	int err;

416 417
	if (snd_BUG_ON(!cap_substream))
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
	ak4117->substream = cap_substream;
	for (idx = 0; idx < AK4117_CONTROLS; idx++) {
		kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117);
		if (kctl == NULL)
			return -ENOMEM;
		kctl->id.device = cap_substream->pcm->device;
		kctl->id.subdevice = cap_substream->number;
		err = snd_ctl_add(ak4117->card, kctl);
		if (err < 0)
			return err;
		ak4117->kctls[idx] = kctl;
	}
	return 0;
}

433
int snd_ak4117_external_rate(struct ak4117 *ak4117)
Linus Torvalds's avatar
Linus Torvalds committed
434 435 436 437 438 439 440
{
	unsigned char rcs1;

	rcs1 = reg_read(ak4117, AK4117_REG_RCS1);
	return external_rate(rcs1);
}

441
int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags)
Linus Torvalds's avatar
Linus Torvalds committed
442
{
443
	struct snd_pcm_runtime *runtime = ak4117->substream ? ak4117->substream->runtime : NULL;
Linus Torvalds's avatar
Linus Torvalds committed
444 445 446 447 448 449 450 451 452 453
	unsigned long _flags;
	int res = 0;
	unsigned char rcs0, rcs1, rcs2;
	unsigned char c0, c1;

	rcs1 = reg_read(ak4117, AK4117_REG_RCS1);
	if (flags & AK4117_CHECK_NO_STAT)
		goto __rate;
	rcs0 = reg_read(ak4117, AK4117_REG_RCS0);
	rcs2 = reg_read(ak4117, AK4117_REG_RCS2);
454
	// printk(KERN_DEBUG "AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2);
Linus Torvalds's avatar
Linus Torvalds committed
455 456
	spin_lock_irqsave(&ak4117->lock, _flags);
	if (rcs0 & AK4117_PAR)
457
		ak4117->errors[AK4117_PARITY_ERRORS]++;
Linus Torvalds's avatar
Linus Torvalds committed
458
	if (rcs0 & AK4117_V)
459
		ak4117->errors[AK4117_V_BIT_ERRORS]++;
Linus Torvalds's avatar
Linus Torvalds committed
460
	if (rcs2 & AK4117_CCRC)
461
		ak4117->errors[AK4117_CCRC_ERRORS]++;
Linus Torvalds's avatar
Linus Torvalds committed
462
	if (rcs2 & AK4117_QCRC)
463
		ak4117->errors[AK4117_QCRC_ERRORS]++;
Linus Torvalds's avatar
Linus Torvalds committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
	c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^
                     (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK));
	c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^
	             (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f));
	ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);
	ak4117->rcs1 = rcs1;
	ak4117->rcs2 = rcs2;
	spin_unlock_irqrestore(&ak4117->lock, _flags);

	if (rcs0 & AK4117_PAR)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id);
	if (rcs0 & AK4117_V)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id);
	if (rcs2 & AK4117_CCRC)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id);
	if (rcs2 & AK4117_QCRC)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id);

	/* rate change */
	if (c1 & 0x0f)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id);

	if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT))
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id);
	if (c0 & AK4117_QINT)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id);

	if (c0 & AK4117_AUDION)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id);
	if (c1 & AK4117_NPCM)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id);
	if (c1 & AK4117_DTSCD)
		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id);
		
	if (ak4117->change_callback && (c0 | c1) != 0)
		ak4117->change_callback(ak4117, c0, c1);

      __rate:
	/* compare rate */
	res = external_rate(rcs1);
	if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) {
		snd_pcm_stream_lock_irqsave(ak4117->substream, _flags);
		if (snd_pcm_running(ak4117->substream)) {
507
			// printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res);
Linus Torvalds's avatar
Linus Torvalds committed
508 509 510 511 512 513 514 515 516
			snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING);
			wake_up(&runtime->sleep);
			res = 1;
		}
		snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags);
	}
	return res;
}

517
static void snd_ak4117_timer(struct timer_list *t)
Linus Torvalds's avatar
Linus Torvalds committed
518
{
519
	struct ak4117 *chip = from_timer(chip, t, timer);
Linus Torvalds's avatar
Linus Torvalds committed
520 521 522 523

	if (chip->init)
		return;
	snd_ak4117_check_rate_and_errors(chip, 0);
524
	mod_timer(&chip->timer, 1 + jiffies);
Linus Torvalds's avatar
Linus Torvalds committed
525 526 527 528 529 530 531 532
}

EXPORT_SYMBOL(snd_ak4117_create);
EXPORT_SYMBOL(snd_ak4117_reg_write);
EXPORT_SYMBOL(snd_ak4117_reinit);
EXPORT_SYMBOL(snd_ak4117_build);
EXPORT_SYMBOL(snd_ak4117_external_rate);
EXPORT_SYMBOL(snd_ak4117_check_rate_and_errors);