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