brintos

brintos / linux-shallow public Read only

0
0
Text · 15.3 KiB · 165fdda Raw
521 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Routines for control of the AK4117 via 4-wire serial interface4 *  IEC958 (S/PDIF) receiver by Asahi Kasei5 *  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/ak4117.h>15#include <sound/asoundef.h>16 17MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");18MODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei");19MODULE_LICENSE("GPL");20 21#define AK4117_ADDR			0x00 /* fixed address */22 23static void snd_ak4117_timer(struct timer_list *t);24 25static 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 32static inline unsigned char reg_read(struct ak4117 *ak4117, unsigned char reg)33{34	return ak4117->read(ak4117->private_data, reg);35}36 37static void snd_ak4117_free(struct ak4117 *chip)38{39	timer_shutdown_sync(&chip->timer);40	kfree(chip);41}42 43static 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 50int 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 91void 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 98void snd_ak4117_reinit(struct ak4117 *chip)99{100	unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg;101 102	del_timer(&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 118static 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 132static 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 142static 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	spin_lock_irq(&chip->lock);148	ucontrol->value.integer.value[0] =149		       chip->errors[kcontrol->private_value];150	chip->errors[kcontrol->private_value] = 0;151	spin_unlock_irq(&chip->lock);152	return 0;153}154 155#define snd_ak4117_in_bit_info		snd_ctl_boolean_mono_info156 157static int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol,158				 struct snd_ctl_elem_value *ucontrol)159{160	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);161	unsigned char reg = kcontrol->private_value & 0xff;162	unsigned char bit = (kcontrol->private_value >> 8) & 0xff;163	unsigned char inv = (kcontrol->private_value >> 31) & 1;164 165	ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;166	return 0;167}168 169static int snd_ak4117_rx_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 = 1;176	return 0;177}178 179static int snd_ak4117_rx_get(struct snd_kcontrol *kcontrol,180			     struct snd_ctl_elem_value *ucontrol)181{182	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);183 184	ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0;185	return 0;186}187 188static int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol,189			     struct snd_ctl_elem_value *ucontrol)190{191	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);192	int change;193	u8 old_val;194	195	spin_lock_irq(&chip->lock);196	old_val = chip->regmap[AK4117_REG_IO];197	change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0);198	if (change)199		reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0));200	spin_unlock_irq(&chip->lock);201	return change;202}203 204static int snd_ak4117_rate_info(struct snd_kcontrol *kcontrol,205				struct snd_ctl_elem_info *uinfo)206{207	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;208	uinfo->count = 1;209	uinfo->value.integer.min = 0;210	uinfo->value.integer.max = 192000;211	return 0;212}213 214static int snd_ak4117_rate_get(struct snd_kcontrol *kcontrol,215			       struct snd_ctl_elem_value *ucontrol)216{217	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);218 219	ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1));220	return 0;221}222 223static int snd_ak4117_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)224{225	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;226	uinfo->count = 1;227	return 0;228}229 230static int snd_ak4117_spdif_get(struct snd_kcontrol *kcontrol,231				struct snd_ctl_elem_value *ucontrol)232{233	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);234	unsigned i;235 236	for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++)237		ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i);238	return 0;239}240 241static int snd_ak4117_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)242{243	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;244	uinfo->count = 1;245	return 0;246}247 248static int snd_ak4117_spdif_mask_get(struct snd_kcontrol *kcontrol,249				      struct snd_ctl_elem_value *ucontrol)250{251	memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE);252	return 0;253}254 255static int snd_ak4117_spdif_pinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)256{257	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;258	uinfo->value.integer.min = 0;259	uinfo->value.integer.max = 0xffff;260	uinfo->count = 4;261	return 0;262}263 264static int snd_ak4117_spdif_pget(struct snd_kcontrol *kcontrol,265				 struct snd_ctl_elem_value *ucontrol)266{267	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);268	unsigned short tmp;269 270	ucontrol->value.integer.value[0] = 0xf8f2;271	ucontrol->value.integer.value[1] = 0x4e1f;272	tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8);273	ucontrol->value.integer.value[2] = tmp;274	tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8);275	ucontrol->value.integer.value[3] = tmp;276	return 0;277}278 279static int snd_ak4117_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)280{281	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;282	uinfo->count = AK4117_REG_QSUB_SIZE;283	return 0;284}285 286static int snd_ak4117_spdif_qget(struct snd_kcontrol *kcontrol,287				 struct snd_ctl_elem_value *ucontrol)288{289	struct ak4117 *chip = snd_kcontrol_chip(kcontrol);290	unsigned i;291 292	for (i = 0; i < AK4117_REG_QSUB_SIZE; i++)293		ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i);294	return 0;295}296 297/* Don't forget to change AK4117_CONTROLS define!!! */298static const struct snd_kcontrol_new snd_ak4117_iec958_controls[] = {299{300	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,301	.name =		"IEC958 Parity Errors",302	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,303	.info =		snd_ak4117_in_error_info,304	.get =		snd_ak4117_in_error_get,305	.private_value = AK4117_PARITY_ERRORS,306},307{308	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,309	.name =		"IEC958 V-Bit Errors",310	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,311	.info =		snd_ak4117_in_error_info,312	.get =		snd_ak4117_in_error_get,313	.private_value = AK4117_V_BIT_ERRORS,314},315{316	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,317	.name =		"IEC958 C-CRC Errors",318	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,319	.info =		snd_ak4117_in_error_info,320	.get =		snd_ak4117_in_error_get,321	.private_value = AK4117_CCRC_ERRORS,322},323{324	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,325	.name =		"IEC958 Q-CRC Errors",326	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,327	.info =		snd_ak4117_in_error_info,328	.get =		snd_ak4117_in_error_get,329	.private_value = AK4117_QCRC_ERRORS,330},331{332	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,333	.name =		"IEC958 External Rate",334	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,335	.info =		snd_ak4117_rate_info,336	.get =		snd_ak4117_rate_get,337},338{339	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,340	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),341	.access =	SNDRV_CTL_ELEM_ACCESS_READ,342	.info =		snd_ak4117_spdif_mask_info,343	.get =		snd_ak4117_spdif_mask_get,344},345{346	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,347	.name =		SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),348	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,349	.info =		snd_ak4117_spdif_info,350	.get =		snd_ak4117_spdif_get,351},352{353	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,354	.name =		"IEC958 Preamble Capture Default",355	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,356	.info =		snd_ak4117_spdif_pinfo,357	.get =		snd_ak4117_spdif_pget,358},359{360	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,361	.name =		"IEC958 Q-subcode Capture Default",362	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,363	.info =		snd_ak4117_spdif_qinfo,364	.get =		snd_ak4117_spdif_qget,365},366{367	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,368	.name =		"IEC958 Audio",369	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,370	.info =		snd_ak4117_in_bit_info,371	.get =		snd_ak4117_in_bit_get,372	.private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0,373},374{375	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,376	.name =		"IEC958 Non-PCM Bitstream",377	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,378	.info =		snd_ak4117_in_bit_info,379	.get =		snd_ak4117_in_bit_get,380	.private_value = (5<<8) | AK4117_REG_RCS1,381},382{383	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,384	.name =		"IEC958 DTS Bitstream",385	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,386	.info =		snd_ak4117_in_bit_info,387	.get =		snd_ak4117_in_bit_get,388	.private_value = (6<<8) | AK4117_REG_RCS1,389},390{391	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,392	.name =		"AK4117 Input Select",393	.access =	SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,394	.info =		snd_ak4117_rx_info,395	.get =		snd_ak4117_rx_get,396	.put =		snd_ak4117_rx_put,397}398};399 400int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *cap_substream)401{402	struct snd_kcontrol *kctl;403	unsigned int idx;404	int err;405 406	if (snd_BUG_ON(!cap_substream))407		return -EINVAL;408	ak4117->substream = cap_substream;409	for (idx = 0; idx < AK4117_CONTROLS; idx++) {410		kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117);411		if (kctl == NULL)412			return -ENOMEM;413		kctl->id.device = cap_substream->pcm->device;414		kctl->id.subdevice = cap_substream->number;415		err = snd_ctl_add(ak4117->card, kctl);416		if (err < 0)417			return err;418		ak4117->kctls[idx] = kctl;419	}420	return 0;421}422 423int snd_ak4117_external_rate(struct ak4117 *ak4117)424{425	unsigned char rcs1;426 427	rcs1 = reg_read(ak4117, AK4117_REG_RCS1);428	return external_rate(rcs1);429}430 431int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags)432{433	struct snd_pcm_runtime *runtime = ak4117->substream ? ak4117->substream->runtime : NULL;434	unsigned long _flags;435	int res = 0;436	unsigned char rcs0, rcs1, rcs2;437	unsigned char c0, c1;438 439	rcs1 = reg_read(ak4117, AK4117_REG_RCS1);440	if (flags & AK4117_CHECK_NO_STAT)441		goto __rate;442	rcs0 = reg_read(ak4117, AK4117_REG_RCS0);443	rcs2 = reg_read(ak4117, AK4117_REG_RCS2);444	spin_lock_irqsave(&ak4117->lock, _flags);445	if (rcs0 & AK4117_PAR)446		ak4117->errors[AK4117_PARITY_ERRORS]++;447	if (rcs0 & AK4117_V)448		ak4117->errors[AK4117_V_BIT_ERRORS]++;449	if (rcs2 & AK4117_CCRC)450		ak4117->errors[AK4117_CCRC_ERRORS]++;451	if (rcs2 & AK4117_QCRC)452		ak4117->errors[AK4117_QCRC_ERRORS]++;453	c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^454                     (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK));455	c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^456	             (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f));457	ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC);458	ak4117->rcs1 = rcs1;459	ak4117->rcs2 = rcs2;460	spin_unlock_irqrestore(&ak4117->lock, _flags);461 462	if (rcs0 & AK4117_PAR)463		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id);464	if (rcs0 & AK4117_V)465		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id);466	if (rcs2 & AK4117_CCRC)467		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id);468	if (rcs2 & AK4117_QCRC)469		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id);470 471	/* rate change */472	if (c1 & 0x0f)473		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id);474 475	if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT))476		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id);477	if (c0 & AK4117_QINT)478		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id);479 480	if (c0 & AK4117_AUDION)481		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id);482	if (c1 & AK4117_NPCM)483		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id);484	if (c1 & AK4117_DTSCD)485		snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id);486		487	if (ak4117->change_callback && (c0 | c1) != 0)488		ak4117->change_callback(ak4117, c0, c1);489 490      __rate:491	/* compare rate */492	res = external_rate(rcs1);493	if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) {494		snd_pcm_stream_lock_irqsave(ak4117->substream, _flags);495		if (snd_pcm_running(ak4117->substream)) {496			snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING);497			wake_up(&runtime->sleep);498			res = 1;499		}500		snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags);501	}502	return res;503}504 505static void snd_ak4117_timer(struct timer_list *t)506{507	struct ak4117 *chip = from_timer(chip, t, timer);508 509	if (chip->init)510		return;511	snd_ak4117_check_rate_and_errors(chip, 0);512	mod_timer(&chip->timer, 1 + jiffies);513}514 515EXPORT_SYMBOL(snd_ak4117_create);516EXPORT_SYMBOL(snd_ak4117_reg_write);517EXPORT_SYMBOL(snd_ak4117_reinit);518EXPORT_SYMBOL(snd_ak4117_build);519EXPORT_SYMBOL(snd_ak4117_external_rate);520EXPORT_SYMBOL(snd_ak4117_check_rate_and_errors);521