162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Routines for control of the AK4117 via 4-wire serial interface 462306a36Sopenharmony_ci * IEC958 (S/PDIF) receiver by Asahi Kasei 562306a36Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <sound/core.h> 1262306a36Sopenharmony_ci#include <sound/control.h> 1362306a36Sopenharmony_ci#include <sound/pcm.h> 1462306a36Sopenharmony_ci#include <sound/ak4117.h> 1562306a36Sopenharmony_ci#include <sound/asoundef.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 1862306a36Sopenharmony_ciMODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei"); 1962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define AK4117_ADDR 0x00 /* fixed address */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void snd_ak4117_timer(struct timer_list *t); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char val) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci ak4117->write(ak4117->private_data, reg, val); 2862306a36Sopenharmony_ci if (reg < sizeof(ak4117->regmap)) 2962306a36Sopenharmony_ci ak4117->regmap[reg] = val; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic inline unsigned char reg_read(struct ak4117 *ak4117, unsigned char reg) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci return ak4117->read(ak4117->private_data, reg); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#if 0 3862306a36Sopenharmony_cistatic void reg_dump(struct ak4117 *ak4117) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci int i; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci printk(KERN_DEBUG "AK4117 REG DUMP:\n"); 4362306a36Sopenharmony_ci for (i = 0; i < 0x1b; i++) 4462306a36Sopenharmony_ci printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic void snd_ak4117_free(struct ak4117 *chip) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci timer_shutdown_sync(&chip->timer); 5162306a36Sopenharmony_ci kfree(chip); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int snd_ak4117_dev_free(struct snd_device *device) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct ak4117 *chip = device->device_data; 5762306a36Sopenharmony_ci snd_ak4117_free(chip); 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciint snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, 6262306a36Sopenharmony_ci const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct ak4117 *chip; 6562306a36Sopenharmony_ci int err = 0; 6662306a36Sopenharmony_ci unsigned char reg; 6762306a36Sopenharmony_ci static const struct snd_device_ops ops = { 6862306a36Sopenharmony_ci .dev_free = snd_ak4117_dev_free, 6962306a36Sopenharmony_ci }; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 7262306a36Sopenharmony_ci if (chip == NULL) 7362306a36Sopenharmony_ci return -ENOMEM; 7462306a36Sopenharmony_ci spin_lock_init(&chip->lock); 7562306a36Sopenharmony_ci chip->card = card; 7662306a36Sopenharmony_ci chip->read = read; 7762306a36Sopenharmony_ci chip->write = write; 7862306a36Sopenharmony_ci chip->private_data = private_data; 7962306a36Sopenharmony_ci timer_setup(&chip->timer, snd_ak4117_timer, 0); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (reg = 0; reg < 5; reg++) 8262306a36Sopenharmony_ci chip->regmap[reg] = pgm[reg]; 8362306a36Sopenharmony_ci snd_ak4117_reinit(chip); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci chip->rcs0 = reg_read(chip, AK4117_REG_RCS0) & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); 8662306a36Sopenharmony_ci chip->rcs1 = reg_read(chip, AK4117_REG_RCS1); 8762306a36Sopenharmony_ci chip->rcs2 = reg_read(chip, AK4117_REG_RCS2); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops); 9062306a36Sopenharmony_ci if (err < 0) 9162306a36Sopenharmony_ci goto __fail; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (r_ak4117) 9462306a36Sopenharmony_ci *r_ak4117 = chip; 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci __fail: 9862306a36Sopenharmony_ci snd_ak4117_free(chip); 9962306a36Sopenharmony_ci return err; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_civoid snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci if (reg >= 5) 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_civoid snd_ak4117_reinit(struct ak4117 *chip) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci del_timer(&chip->timer); 11462306a36Sopenharmony_ci chip->init = 1; 11562306a36Sopenharmony_ci /* bring the chip to reset state and powerdown state */ 11662306a36Sopenharmony_ci reg_write(chip, AK4117_REG_PWRDN, 0); 11762306a36Sopenharmony_ci udelay(200); 11862306a36Sopenharmony_ci /* release reset, but leave powerdown */ 11962306a36Sopenharmony_ci reg_write(chip, AK4117_REG_PWRDN, (old | AK4117_RST) & ~AK4117_PWN); 12062306a36Sopenharmony_ci udelay(200); 12162306a36Sopenharmony_ci for (reg = 1; reg < 5; reg++) 12262306a36Sopenharmony_ci reg_write(chip, reg, chip->regmap[reg]); 12362306a36Sopenharmony_ci /* release powerdown, everything is initialized now */ 12462306a36Sopenharmony_ci reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN); 12562306a36Sopenharmony_ci chip->init = 0; 12662306a36Sopenharmony_ci mod_timer(&chip->timer, 1 + jiffies); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic unsigned int external_rate(unsigned char rcs1) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci switch (rcs1 & (AK4117_FS0|AK4117_FS1|AK4117_FS2|AK4117_FS3)) { 13262306a36Sopenharmony_ci case AK4117_FS_32000HZ: return 32000; 13362306a36Sopenharmony_ci case AK4117_FS_44100HZ: return 44100; 13462306a36Sopenharmony_ci case AK4117_FS_48000HZ: return 48000; 13562306a36Sopenharmony_ci case AK4117_FS_88200HZ: return 88200; 13662306a36Sopenharmony_ci case AK4117_FS_96000HZ: return 96000; 13762306a36Sopenharmony_ci case AK4117_FS_176400HZ: return 176400; 13862306a36Sopenharmony_ci case AK4117_FS_192000HZ: return 192000; 13962306a36Sopenharmony_ci default: return 0; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int snd_ak4117_in_error_info(struct snd_kcontrol *kcontrol, 14462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14762306a36Sopenharmony_ci uinfo->count = 1; 14862306a36Sopenharmony_ci uinfo->value.integer.min = 0; 14962306a36Sopenharmony_ci uinfo->value.integer.max = LONG_MAX; 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol, 15462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 15962306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 16062306a36Sopenharmony_ci chip->errors[kcontrol->private_value]; 16162306a36Sopenharmony_ci chip->errors[kcontrol->private_value] = 0; 16262306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define snd_ak4117_in_bit_info snd_ctl_boolean_mono_info 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol, 16962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 17262306a36Sopenharmony_ci unsigned char reg = kcontrol->private_value & 0xff; 17362306a36Sopenharmony_ci unsigned char bit = (kcontrol->private_value >> 8) & 0xff; 17462306a36Sopenharmony_ci unsigned char inv = (kcontrol->private_value >> 31) & 1; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int snd_ak4117_rx_info(struct snd_kcontrol *kcontrol, 18162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 18462306a36Sopenharmony_ci uinfo->count = 1; 18562306a36Sopenharmony_ci uinfo->value.integer.min = 0; 18662306a36Sopenharmony_ci uinfo->value.integer.max = 1; 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int snd_ak4117_rx_get(struct snd_kcontrol *kcontrol, 19162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0; 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol, 20062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 20362306a36Sopenharmony_ci int change; 20462306a36Sopenharmony_ci u8 old_val; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 20762306a36Sopenharmony_ci old_val = chip->regmap[AK4117_REG_IO]; 20862306a36Sopenharmony_ci change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0); 20962306a36Sopenharmony_ci if (change) 21062306a36Sopenharmony_ci reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0)); 21162306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 21262306a36Sopenharmony_ci return change; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int snd_ak4117_rate_info(struct snd_kcontrol *kcontrol, 21662306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 21962306a36Sopenharmony_ci uinfo->count = 1; 22062306a36Sopenharmony_ci uinfo->value.integer.min = 0; 22162306a36Sopenharmony_ci uinfo->value.integer.max = 192000; 22262306a36Sopenharmony_ci return 0; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int snd_ak4117_rate_get(struct snd_kcontrol *kcontrol, 22662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1)); 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int snd_ak4117_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 23762306a36Sopenharmony_ci uinfo->count = 1; 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int snd_ak4117_spdif_get(struct snd_kcontrol *kcontrol, 24262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 24562306a36Sopenharmony_ci unsigned i; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++) 24862306a36Sopenharmony_ci ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i); 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int snd_ak4117_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 25562306a36Sopenharmony_ci uinfo->count = 1; 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int snd_ak4117_spdif_mask_get(struct snd_kcontrol *kcontrol, 26062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE); 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int snd_ak4117_spdif_pinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 26962306a36Sopenharmony_ci uinfo->value.integer.min = 0; 27062306a36Sopenharmony_ci uinfo->value.integer.max = 0xffff; 27162306a36Sopenharmony_ci uinfo->count = 4; 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int snd_ak4117_spdif_pget(struct snd_kcontrol *kcontrol, 27662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 27962306a36Sopenharmony_ci unsigned short tmp; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 0xf8f2; 28262306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 0x4e1f; 28362306a36Sopenharmony_ci tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8); 28462306a36Sopenharmony_ci ucontrol->value.integer.value[2] = tmp; 28562306a36Sopenharmony_ci tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8); 28662306a36Sopenharmony_ci ucontrol->value.integer.value[3] = tmp; 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int snd_ak4117_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 29362306a36Sopenharmony_ci uinfo->count = AK4117_REG_QSUB_SIZE; 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int snd_ak4117_spdif_qget(struct snd_kcontrol *kcontrol, 29862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 30162306a36Sopenharmony_ci unsigned i; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci for (i = 0; i < AK4117_REG_QSUB_SIZE; i++) 30462306a36Sopenharmony_ci ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i); 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* Don't forget to change AK4117_CONTROLS define!!! */ 30962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ak4117_iec958_controls[] = { 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 31262306a36Sopenharmony_ci .name = "IEC958 Parity Errors", 31362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 31462306a36Sopenharmony_ci .info = snd_ak4117_in_error_info, 31562306a36Sopenharmony_ci .get = snd_ak4117_in_error_get, 31662306a36Sopenharmony_ci .private_value = AK4117_PARITY_ERRORS, 31762306a36Sopenharmony_ci}, 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 32062306a36Sopenharmony_ci .name = "IEC958 V-Bit Errors", 32162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 32262306a36Sopenharmony_ci .info = snd_ak4117_in_error_info, 32362306a36Sopenharmony_ci .get = snd_ak4117_in_error_get, 32462306a36Sopenharmony_ci .private_value = AK4117_V_BIT_ERRORS, 32562306a36Sopenharmony_ci}, 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 32862306a36Sopenharmony_ci .name = "IEC958 C-CRC Errors", 32962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 33062306a36Sopenharmony_ci .info = snd_ak4117_in_error_info, 33162306a36Sopenharmony_ci .get = snd_ak4117_in_error_get, 33262306a36Sopenharmony_ci .private_value = AK4117_CCRC_ERRORS, 33362306a36Sopenharmony_ci}, 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 33662306a36Sopenharmony_ci .name = "IEC958 Q-CRC Errors", 33762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 33862306a36Sopenharmony_ci .info = snd_ak4117_in_error_info, 33962306a36Sopenharmony_ci .get = snd_ak4117_in_error_get, 34062306a36Sopenharmony_ci .private_value = AK4117_QCRC_ERRORS, 34162306a36Sopenharmony_ci}, 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 34462306a36Sopenharmony_ci .name = "IEC958 External Rate", 34562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 34662306a36Sopenharmony_ci .info = snd_ak4117_rate_info, 34762306a36Sopenharmony_ci .get = snd_ak4117_rate_get, 34862306a36Sopenharmony_ci}, 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 35162306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), 35262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 35362306a36Sopenharmony_ci .info = snd_ak4117_spdif_mask_info, 35462306a36Sopenharmony_ci .get = snd_ak4117_spdif_mask_get, 35562306a36Sopenharmony_ci}, 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 35862306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), 35962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 36062306a36Sopenharmony_ci .info = snd_ak4117_spdif_info, 36162306a36Sopenharmony_ci .get = snd_ak4117_spdif_get, 36262306a36Sopenharmony_ci}, 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 36562306a36Sopenharmony_ci .name = "IEC958 Preamble Capture Default", 36662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 36762306a36Sopenharmony_ci .info = snd_ak4117_spdif_pinfo, 36862306a36Sopenharmony_ci .get = snd_ak4117_spdif_pget, 36962306a36Sopenharmony_ci}, 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 37262306a36Sopenharmony_ci .name = "IEC958 Q-subcode Capture Default", 37362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 37462306a36Sopenharmony_ci .info = snd_ak4117_spdif_qinfo, 37562306a36Sopenharmony_ci .get = snd_ak4117_spdif_qget, 37662306a36Sopenharmony_ci}, 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 37962306a36Sopenharmony_ci .name = "IEC958 Audio", 38062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 38162306a36Sopenharmony_ci .info = snd_ak4117_in_bit_info, 38262306a36Sopenharmony_ci .get = snd_ak4117_in_bit_get, 38362306a36Sopenharmony_ci .private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0, 38462306a36Sopenharmony_ci}, 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 38762306a36Sopenharmony_ci .name = "IEC958 Non-PCM Bitstream", 38862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 38962306a36Sopenharmony_ci .info = snd_ak4117_in_bit_info, 39062306a36Sopenharmony_ci .get = snd_ak4117_in_bit_get, 39162306a36Sopenharmony_ci .private_value = (5<<8) | AK4117_REG_RCS1, 39262306a36Sopenharmony_ci}, 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 39562306a36Sopenharmony_ci .name = "IEC958 DTS Bitstream", 39662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 39762306a36Sopenharmony_ci .info = snd_ak4117_in_bit_info, 39862306a36Sopenharmony_ci .get = snd_ak4117_in_bit_get, 39962306a36Sopenharmony_ci .private_value = (6<<8) | AK4117_REG_RCS1, 40062306a36Sopenharmony_ci}, 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 40362306a36Sopenharmony_ci .name = "AK4117 Input Select", 40462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE, 40562306a36Sopenharmony_ci .info = snd_ak4117_rx_info, 40662306a36Sopenharmony_ci .get = snd_ak4117_rx_get, 40762306a36Sopenharmony_ci .put = snd_ak4117_rx_put, 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ciint snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *cap_substream) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct snd_kcontrol *kctl; 41462306a36Sopenharmony_ci unsigned int idx; 41562306a36Sopenharmony_ci int err; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (snd_BUG_ON(!cap_substream)) 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci ak4117->substream = cap_substream; 42062306a36Sopenharmony_ci for (idx = 0; idx < AK4117_CONTROLS; idx++) { 42162306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117); 42262306a36Sopenharmony_ci if (kctl == NULL) 42362306a36Sopenharmony_ci return -ENOMEM; 42462306a36Sopenharmony_ci kctl->id.device = cap_substream->pcm->device; 42562306a36Sopenharmony_ci kctl->id.subdevice = cap_substream->number; 42662306a36Sopenharmony_ci err = snd_ctl_add(ak4117->card, kctl); 42762306a36Sopenharmony_ci if (err < 0) 42862306a36Sopenharmony_ci return err; 42962306a36Sopenharmony_ci ak4117->kctls[idx] = kctl; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ciint snd_ak4117_external_rate(struct ak4117 *ak4117) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci unsigned char rcs1; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci rcs1 = reg_read(ak4117, AK4117_REG_RCS1); 43962306a36Sopenharmony_ci return external_rate(rcs1); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ciint snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = ak4117->substream ? ak4117->substream->runtime : NULL; 44562306a36Sopenharmony_ci unsigned long _flags; 44662306a36Sopenharmony_ci int res = 0; 44762306a36Sopenharmony_ci unsigned char rcs0, rcs1, rcs2; 44862306a36Sopenharmony_ci unsigned char c0, c1; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci rcs1 = reg_read(ak4117, AK4117_REG_RCS1); 45162306a36Sopenharmony_ci if (flags & AK4117_CHECK_NO_STAT) 45262306a36Sopenharmony_ci goto __rate; 45362306a36Sopenharmony_ci rcs0 = reg_read(ak4117, AK4117_REG_RCS0); 45462306a36Sopenharmony_ci rcs2 = reg_read(ak4117, AK4117_REG_RCS2); 45562306a36Sopenharmony_ci // printk(KERN_DEBUG "AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2); 45662306a36Sopenharmony_ci spin_lock_irqsave(&ak4117->lock, _flags); 45762306a36Sopenharmony_ci if (rcs0 & AK4117_PAR) 45862306a36Sopenharmony_ci ak4117->errors[AK4117_PARITY_ERRORS]++; 45962306a36Sopenharmony_ci if (rcs0 & AK4117_V) 46062306a36Sopenharmony_ci ak4117->errors[AK4117_V_BIT_ERRORS]++; 46162306a36Sopenharmony_ci if (rcs2 & AK4117_CCRC) 46262306a36Sopenharmony_ci ak4117->errors[AK4117_CCRC_ERRORS]++; 46362306a36Sopenharmony_ci if (rcs2 & AK4117_QCRC) 46462306a36Sopenharmony_ci ak4117->errors[AK4117_QCRC_ERRORS]++; 46562306a36Sopenharmony_ci c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^ 46662306a36Sopenharmony_ci (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)); 46762306a36Sopenharmony_ci c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^ 46862306a36Sopenharmony_ci (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)); 46962306a36Sopenharmony_ci ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); 47062306a36Sopenharmony_ci ak4117->rcs1 = rcs1; 47162306a36Sopenharmony_ci ak4117->rcs2 = rcs2; 47262306a36Sopenharmony_ci spin_unlock_irqrestore(&ak4117->lock, _flags); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (rcs0 & AK4117_PAR) 47562306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id); 47662306a36Sopenharmony_ci if (rcs0 & AK4117_V) 47762306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id); 47862306a36Sopenharmony_ci if (rcs2 & AK4117_CCRC) 47962306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id); 48062306a36Sopenharmony_ci if (rcs2 & AK4117_QCRC) 48162306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* rate change */ 48462306a36Sopenharmony_ci if (c1 & 0x0f) 48562306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT)) 48862306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id); 48962306a36Sopenharmony_ci if (c0 & AK4117_QINT) 49062306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (c0 & AK4117_AUDION) 49362306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id); 49462306a36Sopenharmony_ci if (c1 & AK4117_NPCM) 49562306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id); 49662306a36Sopenharmony_ci if (c1 & AK4117_DTSCD) 49762306a36Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (ak4117->change_callback && (c0 | c1) != 0) 50062306a36Sopenharmony_ci ak4117->change_callback(ak4117, c0, c1); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci __rate: 50362306a36Sopenharmony_ci /* compare rate */ 50462306a36Sopenharmony_ci res = external_rate(rcs1); 50562306a36Sopenharmony_ci if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) { 50662306a36Sopenharmony_ci snd_pcm_stream_lock_irqsave(ak4117->substream, _flags); 50762306a36Sopenharmony_ci if (snd_pcm_running(ak4117->substream)) { 50862306a36Sopenharmony_ci // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res); 50962306a36Sopenharmony_ci snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING); 51062306a36Sopenharmony_ci wake_up(&runtime->sleep); 51162306a36Sopenharmony_ci res = 1; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci return res; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void snd_ak4117_timer(struct timer_list *t) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct ak4117 *chip = from_timer(chip, t, timer); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (chip->init) 52362306a36Sopenharmony_ci return; 52462306a36Sopenharmony_ci snd_ak4117_check_rate_and_errors(chip, 0); 52562306a36Sopenharmony_ci mod_timer(&chip->timer, 1 + jiffies); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_create); 52962306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_reg_write); 53062306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_reinit); 53162306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_build); 53262306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_external_rate); 53362306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_check_rate_and_errors); 534