162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Routines for control of the AK4113 via I2C/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 * Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <sound/core.h> 1362306a36Sopenharmony_ci#include <sound/control.h> 1462306a36Sopenharmony_ci#include <sound/pcm.h> 1562306a36Sopenharmony_ci#include <sound/ak4113.h> 1662306a36Sopenharmony_ci#include <sound/asoundef.h> 1762306a36Sopenharmony_ci#include <sound/info.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciMODULE_AUTHOR("Pavel Hofman <pavel.hofman@ivitera.com>"); 2062306a36Sopenharmony_ciMODULE_DESCRIPTION("AK4113 IEC958 (S/PDIF) receiver by Asahi Kasei"); 2162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define AK4113_ADDR 0x00 /* fixed address */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void ak4113_stats(struct work_struct *work); 2662306a36Sopenharmony_cistatic void ak4113_init_regs(struct ak4113 *chip); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void reg_write(struct ak4113 *ak4113, unsigned char reg, 3062306a36Sopenharmony_ci unsigned char val) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci ak4113->write(ak4113->private_data, reg, val); 3362306a36Sopenharmony_ci if (reg < sizeof(ak4113->regmap)) 3462306a36Sopenharmony_ci ak4113->regmap[reg] = val; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci return ak4113->read(ak4113->private_data, reg); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void snd_ak4113_free(struct ak4113 *chip) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci atomic_inc(&chip->wq_processing); /* don't schedule new work */ 4562306a36Sopenharmony_ci cancel_delayed_work_sync(&chip->work); 4662306a36Sopenharmony_ci kfree(chip); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int snd_ak4113_dev_free(struct snd_device *device) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct ak4113 *chip = device->device_data; 5262306a36Sopenharmony_ci snd_ak4113_free(chip); 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciint snd_ak4113_create(struct snd_card *card, ak4113_read_t *read, 5762306a36Sopenharmony_ci ak4113_write_t *write, const unsigned char *pgm, 5862306a36Sopenharmony_ci void *private_data, struct ak4113 **r_ak4113) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct ak4113 *chip; 6162306a36Sopenharmony_ci int err; 6262306a36Sopenharmony_ci unsigned char reg; 6362306a36Sopenharmony_ci static const struct snd_device_ops ops = { 6462306a36Sopenharmony_ci .dev_free = snd_ak4113_dev_free, 6562306a36Sopenharmony_ci }; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 6862306a36Sopenharmony_ci if (chip == NULL) 6962306a36Sopenharmony_ci return -ENOMEM; 7062306a36Sopenharmony_ci spin_lock_init(&chip->lock); 7162306a36Sopenharmony_ci chip->card = card; 7262306a36Sopenharmony_ci chip->read = read; 7362306a36Sopenharmony_ci chip->write = write; 7462306a36Sopenharmony_ci chip->private_data = private_data; 7562306a36Sopenharmony_ci INIT_DELAYED_WORK(&chip->work, ak4113_stats); 7662306a36Sopenharmony_ci atomic_set(&chip->wq_processing, 0); 7762306a36Sopenharmony_ci mutex_init(&chip->reinit_mutex); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) 8062306a36Sopenharmony_ci chip->regmap[reg] = pgm[reg]; 8162306a36Sopenharmony_ci ak4113_init_regs(chip); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci chip->rcs0 = reg_read(chip, AK4113_REG_RCS0) & ~(AK4113_QINT | 8462306a36Sopenharmony_ci AK4113_CINT | AK4113_STC); 8562306a36Sopenharmony_ci chip->rcs1 = reg_read(chip, AK4113_REG_RCS1); 8662306a36Sopenharmony_ci chip->rcs2 = reg_read(chip, AK4113_REG_RCS2); 8762306a36Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops); 8862306a36Sopenharmony_ci if (err < 0) 8962306a36Sopenharmony_ci goto __fail; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (r_ak4113) 9262306a36Sopenharmony_ci *r_ak4113 = chip; 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci__fail: 9662306a36Sopenharmony_ci snd_ak4113_free(chip); 9762306a36Sopenharmony_ci return err; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_create); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_civoid snd_ak4113_reg_write(struct ak4113 *chip, unsigned char reg, 10262306a36Sopenharmony_ci unsigned char mask, unsigned char val) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci if (reg >= AK4113_WRITABLE_REGS) 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_reg_write); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void ak4113_init_regs(struct ak4113 *chip) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci unsigned char old = chip->regmap[AK4113_REG_PWRDN], reg; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* bring the chip to reset state and powerdown state */ 11562306a36Sopenharmony_ci reg_write(chip, AK4113_REG_PWRDN, old & ~(AK4113_RST|AK4113_PWN)); 11662306a36Sopenharmony_ci udelay(200); 11762306a36Sopenharmony_ci /* release reset, but leave powerdown */ 11862306a36Sopenharmony_ci reg_write(chip, AK4113_REG_PWRDN, (old | AK4113_RST) & ~AK4113_PWN); 11962306a36Sopenharmony_ci udelay(200); 12062306a36Sopenharmony_ci for (reg = 1; reg < AK4113_WRITABLE_REGS; reg++) 12162306a36Sopenharmony_ci reg_write(chip, reg, chip->regmap[reg]); 12262306a36Sopenharmony_ci /* release powerdown, everything is initialized now */ 12362306a36Sopenharmony_ci reg_write(chip, AK4113_REG_PWRDN, old | AK4113_RST | AK4113_PWN); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_civoid snd_ak4113_reinit(struct ak4113 *chip) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci if (atomic_inc_return(&chip->wq_processing) == 1) 12962306a36Sopenharmony_ci cancel_delayed_work_sync(&chip->work); 13062306a36Sopenharmony_ci mutex_lock(&chip->reinit_mutex); 13162306a36Sopenharmony_ci ak4113_init_regs(chip); 13262306a36Sopenharmony_ci mutex_unlock(&chip->reinit_mutex); 13362306a36Sopenharmony_ci /* bring up statistics / event queing */ 13462306a36Sopenharmony_ci if (atomic_dec_and_test(&chip->wq_processing)) 13562306a36Sopenharmony_ci schedule_delayed_work(&chip->work, HZ / 10); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_reinit); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic unsigned int external_rate(unsigned char rcs1) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci switch (rcs1 & (AK4113_FS0|AK4113_FS1|AK4113_FS2|AK4113_FS3)) { 14262306a36Sopenharmony_ci case AK4113_FS_8000HZ: 14362306a36Sopenharmony_ci return 8000; 14462306a36Sopenharmony_ci case AK4113_FS_11025HZ: 14562306a36Sopenharmony_ci return 11025; 14662306a36Sopenharmony_ci case AK4113_FS_16000HZ: 14762306a36Sopenharmony_ci return 16000; 14862306a36Sopenharmony_ci case AK4113_FS_22050HZ: 14962306a36Sopenharmony_ci return 22050; 15062306a36Sopenharmony_ci case AK4113_FS_24000HZ: 15162306a36Sopenharmony_ci return 24000; 15262306a36Sopenharmony_ci case AK4113_FS_32000HZ: 15362306a36Sopenharmony_ci return 32000; 15462306a36Sopenharmony_ci case AK4113_FS_44100HZ: 15562306a36Sopenharmony_ci return 44100; 15662306a36Sopenharmony_ci case AK4113_FS_48000HZ: 15762306a36Sopenharmony_ci return 48000; 15862306a36Sopenharmony_ci case AK4113_FS_64000HZ: 15962306a36Sopenharmony_ci return 64000; 16062306a36Sopenharmony_ci case AK4113_FS_88200HZ: 16162306a36Sopenharmony_ci return 88200; 16262306a36Sopenharmony_ci case AK4113_FS_96000HZ: 16362306a36Sopenharmony_ci return 96000; 16462306a36Sopenharmony_ci case AK4113_FS_176400HZ: 16562306a36Sopenharmony_ci return 176400; 16662306a36Sopenharmony_ci case AK4113_FS_192000HZ: 16762306a36Sopenharmony_ci return 192000; 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int snd_ak4113_in_error_info(struct snd_kcontrol *kcontrol, 17462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 17762306a36Sopenharmony_ci uinfo->count = 1; 17862306a36Sopenharmony_ci uinfo->value.integer.min = 0; 17962306a36Sopenharmony_ci uinfo->value.integer.max = LONG_MAX; 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol, 18462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 18962306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 19062306a36Sopenharmony_ci chip->errors[kcontrol->private_value]; 19162306a36Sopenharmony_ci chip->errors[kcontrol->private_value] = 0; 19262306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#define snd_ak4113_in_bit_info snd_ctl_boolean_mono_info 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int snd_ak4113_in_bit_get(struct snd_kcontrol *kcontrol, 19962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 20262306a36Sopenharmony_ci unsigned char reg = kcontrol->private_value & 0xff; 20362306a36Sopenharmony_ci unsigned char bit = (kcontrol->private_value >> 8) & 0xff; 20462306a36Sopenharmony_ci unsigned char inv = (kcontrol->private_value >> 31) & 1; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 20762306a36Sopenharmony_ci ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int snd_ak4113_rx_info(struct snd_kcontrol *kcontrol, 21262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 21562306a36Sopenharmony_ci uinfo->count = 1; 21662306a36Sopenharmony_ci uinfo->value.integer.min = 0; 21762306a36Sopenharmony_ci uinfo->value.integer.max = 5; 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int snd_ak4113_rx_get(struct snd_kcontrol *kcontrol, 22262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 22762306a36Sopenharmony_ci (AK4113_IPS(chip->regmap[AK4113_REG_IO1])); 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol, 23262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 23562306a36Sopenharmony_ci int change; 23662306a36Sopenharmony_ci u8 old_val; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci spin_lock_irq(&chip->lock); 23962306a36Sopenharmony_ci old_val = chip->regmap[AK4113_REG_IO1]; 24062306a36Sopenharmony_ci change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val); 24162306a36Sopenharmony_ci if (change) 24262306a36Sopenharmony_ci reg_write(chip, AK4113_REG_IO1, 24362306a36Sopenharmony_ci (old_val & (~AK4113_IPS(0xff))) | 24462306a36Sopenharmony_ci (AK4113_IPS(ucontrol->value.integer.value[0]))); 24562306a36Sopenharmony_ci spin_unlock_irq(&chip->lock); 24662306a36Sopenharmony_ci return change; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int snd_ak4113_rate_info(struct snd_kcontrol *kcontrol, 25062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 25362306a36Sopenharmony_ci uinfo->count = 1; 25462306a36Sopenharmony_ci uinfo->value.integer.min = 0; 25562306a36Sopenharmony_ci uinfo->value.integer.max = 192000; 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int snd_ak4113_rate_get(struct snd_kcontrol *kcontrol, 26062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = external_rate(reg_read(chip, 26562306a36Sopenharmony_ci AK4113_REG_RCS1)); 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int snd_ak4113_spdif_info(struct snd_kcontrol *kcontrol, 27062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 27362306a36Sopenharmony_ci uinfo->count = 1; 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int snd_ak4113_spdif_get(struct snd_kcontrol *kcontrol, 27862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 28162306a36Sopenharmony_ci unsigned i; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci for (i = 0; i < AK4113_REG_RXCSB_SIZE; i++) 28462306a36Sopenharmony_ci ucontrol->value.iec958.status[i] = reg_read(chip, 28562306a36Sopenharmony_ci AK4113_REG_RXCSB0 + i); 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int snd_ak4113_spdif_mask_info(struct snd_kcontrol *kcontrol, 29062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 29362306a36Sopenharmony_ci uinfo->count = 1; 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int snd_ak4113_spdif_mask_get(struct snd_kcontrol *kcontrol, 29862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci memset(ucontrol->value.iec958.status, 0xff, AK4113_REG_RXCSB_SIZE); 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int snd_ak4113_spdif_pinfo(struct snd_kcontrol *kcontrol, 30562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 30862306a36Sopenharmony_ci uinfo->value.integer.min = 0; 30962306a36Sopenharmony_ci uinfo->value.integer.max = 0xffff; 31062306a36Sopenharmony_ci uinfo->count = 4; 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int snd_ak4113_spdif_pget(struct snd_kcontrol *kcontrol, 31562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 31862306a36Sopenharmony_ci unsigned short tmp; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 0xf8f2; 32162306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 0x4e1f; 32262306a36Sopenharmony_ci tmp = reg_read(chip, AK4113_REG_Pc0) | 32362306a36Sopenharmony_ci (reg_read(chip, AK4113_REG_Pc1) << 8); 32462306a36Sopenharmony_ci ucontrol->value.integer.value[2] = tmp; 32562306a36Sopenharmony_ci tmp = reg_read(chip, AK4113_REG_Pd0) | 32662306a36Sopenharmony_ci (reg_read(chip, AK4113_REG_Pd1) << 8); 32762306a36Sopenharmony_ci ucontrol->value.integer.value[3] = tmp; 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int snd_ak4113_spdif_qinfo(struct snd_kcontrol *kcontrol, 33262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 33562306a36Sopenharmony_ci uinfo->count = AK4113_REG_QSUB_SIZE; 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int snd_ak4113_spdif_qget(struct snd_kcontrol *kcontrol, 34062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 34362306a36Sopenharmony_ci unsigned i; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci for (i = 0; i < AK4113_REG_QSUB_SIZE; i++) 34662306a36Sopenharmony_ci ucontrol->value.bytes.data[i] = reg_read(chip, 34762306a36Sopenharmony_ci AK4113_REG_QSUB_ADDR + i); 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* Don't forget to change AK4113_CONTROLS define!!! */ 35262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 35562306a36Sopenharmony_ci .name = "IEC958 Parity Errors", 35662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 35762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 35862306a36Sopenharmony_ci .info = snd_ak4113_in_error_info, 35962306a36Sopenharmony_ci .get = snd_ak4113_in_error_get, 36062306a36Sopenharmony_ci .private_value = AK4113_PARITY_ERRORS, 36162306a36Sopenharmony_ci}, 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 36462306a36Sopenharmony_ci .name = "IEC958 V-Bit Errors", 36562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 36662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 36762306a36Sopenharmony_ci .info = snd_ak4113_in_error_info, 36862306a36Sopenharmony_ci .get = snd_ak4113_in_error_get, 36962306a36Sopenharmony_ci .private_value = AK4113_V_BIT_ERRORS, 37062306a36Sopenharmony_ci}, 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 37362306a36Sopenharmony_ci .name = "IEC958 C-CRC Errors", 37462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 37562306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 37662306a36Sopenharmony_ci .info = snd_ak4113_in_error_info, 37762306a36Sopenharmony_ci .get = snd_ak4113_in_error_get, 37862306a36Sopenharmony_ci .private_value = AK4113_CCRC_ERRORS, 37962306a36Sopenharmony_ci}, 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 38262306a36Sopenharmony_ci .name = "IEC958 Q-CRC Errors", 38362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 38462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 38562306a36Sopenharmony_ci .info = snd_ak4113_in_error_info, 38662306a36Sopenharmony_ci .get = snd_ak4113_in_error_get, 38762306a36Sopenharmony_ci .private_value = AK4113_QCRC_ERRORS, 38862306a36Sopenharmony_ci}, 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 39162306a36Sopenharmony_ci .name = "IEC958 External Rate", 39262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 39362306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 39462306a36Sopenharmony_ci .info = snd_ak4113_rate_info, 39562306a36Sopenharmony_ci .get = snd_ak4113_rate_get, 39662306a36Sopenharmony_ci}, 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 39962306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), 40062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 40162306a36Sopenharmony_ci .info = snd_ak4113_spdif_mask_info, 40262306a36Sopenharmony_ci .get = snd_ak4113_spdif_mask_get, 40362306a36Sopenharmony_ci}, 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 40662306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 40762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 40862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 40962306a36Sopenharmony_ci .info = snd_ak4113_spdif_info, 41062306a36Sopenharmony_ci .get = snd_ak4113_spdif_get, 41162306a36Sopenharmony_ci}, 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 41462306a36Sopenharmony_ci .name = "IEC958 Preamble Capture Default", 41562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 41662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 41762306a36Sopenharmony_ci .info = snd_ak4113_spdif_pinfo, 41862306a36Sopenharmony_ci .get = snd_ak4113_spdif_pget, 41962306a36Sopenharmony_ci}, 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 42262306a36Sopenharmony_ci .name = "IEC958 Q-subcode Capture Default", 42362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 42462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 42562306a36Sopenharmony_ci .info = snd_ak4113_spdif_qinfo, 42662306a36Sopenharmony_ci .get = snd_ak4113_spdif_qget, 42762306a36Sopenharmony_ci}, 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 43062306a36Sopenharmony_ci .name = "IEC958 Audio", 43162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 43262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 43362306a36Sopenharmony_ci .info = snd_ak4113_in_bit_info, 43462306a36Sopenharmony_ci .get = snd_ak4113_in_bit_get, 43562306a36Sopenharmony_ci .private_value = (1<<31) | (1<<8) | AK4113_REG_RCS0, 43662306a36Sopenharmony_ci}, 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 43962306a36Sopenharmony_ci .name = "IEC958 Non-PCM Bitstream", 44062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 44162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 44262306a36Sopenharmony_ci .info = snd_ak4113_in_bit_info, 44362306a36Sopenharmony_ci .get = snd_ak4113_in_bit_get, 44462306a36Sopenharmony_ci .private_value = (0<<8) | AK4113_REG_RCS1, 44562306a36Sopenharmony_ci}, 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 44862306a36Sopenharmony_ci .name = "IEC958 DTS Bitstream", 44962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 45062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 45162306a36Sopenharmony_ci .info = snd_ak4113_in_bit_info, 45262306a36Sopenharmony_ci .get = snd_ak4113_in_bit_get, 45362306a36Sopenharmony_ci .private_value = (1<<8) | AK4113_REG_RCS1, 45462306a36Sopenharmony_ci}, 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 45762306a36Sopenharmony_ci .name = "AK4113 Input Select", 45862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 45962306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_WRITE, 46062306a36Sopenharmony_ci .info = snd_ak4113_rx_info, 46162306a36Sopenharmony_ci .get = snd_ak4113_rx_get, 46262306a36Sopenharmony_ci .put = snd_ak4113_rx_put, 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci}; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic void snd_ak4113_proc_regs_read(struct snd_info_entry *entry, 46762306a36Sopenharmony_ci struct snd_info_buffer *buffer) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct ak4113 *ak4113 = entry->private_data; 47062306a36Sopenharmony_ci int reg, val; 47162306a36Sopenharmony_ci /* all ak4113 registers 0x00 - 0x1c */ 47262306a36Sopenharmony_ci for (reg = 0; reg < 0x1d; reg++) { 47362306a36Sopenharmony_ci val = reg_read(ak4113, reg); 47462306a36Sopenharmony_ci snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic void snd_ak4113_proc_init(struct ak4113 *ak4113) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci snd_card_ro_proc_new(ak4113->card, "ak4113", ak4113, 48162306a36Sopenharmony_ci snd_ak4113_proc_regs_read); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ciint snd_ak4113_build(struct ak4113 *ak4113, 48562306a36Sopenharmony_ci struct snd_pcm_substream *cap_substream) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct snd_kcontrol *kctl; 48862306a36Sopenharmony_ci unsigned int idx; 48962306a36Sopenharmony_ci int err; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (snd_BUG_ON(!cap_substream)) 49262306a36Sopenharmony_ci return -EINVAL; 49362306a36Sopenharmony_ci ak4113->substream = cap_substream; 49462306a36Sopenharmony_ci for (idx = 0; idx < AK4113_CONTROLS; idx++) { 49562306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ak4113_iec958_controls[idx], ak4113); 49662306a36Sopenharmony_ci if (kctl == NULL) 49762306a36Sopenharmony_ci return -ENOMEM; 49862306a36Sopenharmony_ci kctl->id.device = cap_substream->pcm->device; 49962306a36Sopenharmony_ci kctl->id.subdevice = cap_substream->number; 50062306a36Sopenharmony_ci err = snd_ctl_add(ak4113->card, kctl); 50162306a36Sopenharmony_ci if (err < 0) 50262306a36Sopenharmony_ci return err; 50362306a36Sopenharmony_ci ak4113->kctls[idx] = kctl; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci snd_ak4113_proc_init(ak4113); 50662306a36Sopenharmony_ci /* trigger workq */ 50762306a36Sopenharmony_ci schedule_delayed_work(&ak4113->work, HZ / 10); 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_build); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ciint snd_ak4113_external_rate(struct ak4113 *ak4113) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci unsigned char rcs1; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci rcs1 = reg_read(ak4113, AK4113_REG_RCS1); 51762306a36Sopenharmony_ci return external_rate(rcs1); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_external_rate); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ciint snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = 52462306a36Sopenharmony_ci ak4113->substream ? ak4113->substream->runtime : NULL; 52562306a36Sopenharmony_ci unsigned long _flags; 52662306a36Sopenharmony_ci int res = 0; 52762306a36Sopenharmony_ci unsigned char rcs0, rcs1, rcs2; 52862306a36Sopenharmony_ci unsigned char c0, c1; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci rcs1 = reg_read(ak4113, AK4113_REG_RCS1); 53162306a36Sopenharmony_ci if (flags & AK4113_CHECK_NO_STAT) 53262306a36Sopenharmony_ci goto __rate; 53362306a36Sopenharmony_ci rcs0 = reg_read(ak4113, AK4113_REG_RCS0); 53462306a36Sopenharmony_ci rcs2 = reg_read(ak4113, AK4113_REG_RCS2); 53562306a36Sopenharmony_ci spin_lock_irqsave(&ak4113->lock, _flags); 53662306a36Sopenharmony_ci if (rcs0 & AK4113_PAR) 53762306a36Sopenharmony_ci ak4113->errors[AK4113_PARITY_ERRORS]++; 53862306a36Sopenharmony_ci if (rcs0 & AK4113_V) 53962306a36Sopenharmony_ci ak4113->errors[AK4113_V_BIT_ERRORS]++; 54062306a36Sopenharmony_ci if (rcs2 & AK4113_CCRC) 54162306a36Sopenharmony_ci ak4113->errors[AK4113_CCRC_ERRORS]++; 54262306a36Sopenharmony_ci if (rcs2 & AK4113_QCRC) 54362306a36Sopenharmony_ci ak4113->errors[AK4113_QCRC_ERRORS]++; 54462306a36Sopenharmony_ci c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | 54562306a36Sopenharmony_ci AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^ 54662306a36Sopenharmony_ci (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | 54762306a36Sopenharmony_ci AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)); 54862306a36Sopenharmony_ci c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | 54962306a36Sopenharmony_ci AK4113_DAT | 0xf0)) ^ 55062306a36Sopenharmony_ci (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | 55162306a36Sopenharmony_ci AK4113_DAT | 0xf0)); 55262306a36Sopenharmony_ci ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC); 55362306a36Sopenharmony_ci ak4113->rcs1 = rcs1; 55462306a36Sopenharmony_ci ak4113->rcs2 = rcs2; 55562306a36Sopenharmony_ci spin_unlock_irqrestore(&ak4113->lock, _flags); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (rcs0 & AK4113_PAR) 55862306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 55962306a36Sopenharmony_ci &ak4113->kctls[0]->id); 56062306a36Sopenharmony_ci if (rcs0 & AK4113_V) 56162306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 56262306a36Sopenharmony_ci &ak4113->kctls[1]->id); 56362306a36Sopenharmony_ci if (rcs2 & AK4113_CCRC) 56462306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 56562306a36Sopenharmony_ci &ak4113->kctls[2]->id); 56662306a36Sopenharmony_ci if (rcs2 & AK4113_QCRC) 56762306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 56862306a36Sopenharmony_ci &ak4113->kctls[3]->id); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* rate change */ 57162306a36Sopenharmony_ci if (c1 & 0xf0) 57262306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 57362306a36Sopenharmony_ci &ak4113->kctls[4]->id); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if ((c1 & AK4113_PEM) | (c0 & AK4113_CINT)) 57662306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 57762306a36Sopenharmony_ci &ak4113->kctls[6]->id); 57862306a36Sopenharmony_ci if (c0 & AK4113_QINT) 57962306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 58062306a36Sopenharmony_ci &ak4113->kctls[8]->id); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (c0 & AK4113_AUDION) 58362306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 58462306a36Sopenharmony_ci &ak4113->kctls[9]->id); 58562306a36Sopenharmony_ci if (c1 & AK4113_NPCM) 58662306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 58762306a36Sopenharmony_ci &ak4113->kctls[10]->id); 58862306a36Sopenharmony_ci if (c1 & AK4113_DTSCD) 58962306a36Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 59062306a36Sopenharmony_ci &ak4113->kctls[11]->id); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (ak4113->change_callback && (c0 | c1) != 0) 59362306a36Sopenharmony_ci ak4113->change_callback(ak4113, c0, c1); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci__rate: 59662306a36Sopenharmony_ci /* compare rate */ 59762306a36Sopenharmony_ci res = external_rate(rcs1); 59862306a36Sopenharmony_ci if (!(flags & AK4113_CHECK_NO_RATE) && runtime && 59962306a36Sopenharmony_ci (runtime->rate != res)) { 60062306a36Sopenharmony_ci snd_pcm_stream_lock_irqsave(ak4113->substream, _flags); 60162306a36Sopenharmony_ci if (snd_pcm_running(ak4113->substream)) { 60262306a36Sopenharmony_ci /*printk(KERN_DEBUG "rate changed (%i <- %i)\n", 60362306a36Sopenharmony_ci * runtime->rate, res); */ 60462306a36Sopenharmony_ci snd_pcm_stop(ak4113->substream, 60562306a36Sopenharmony_ci SNDRV_PCM_STATE_DRAINING); 60662306a36Sopenharmony_ci wake_up(&runtime->sleep); 60762306a36Sopenharmony_ci res = 1; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci snd_pcm_stream_unlock_irqrestore(ak4113->substream, _flags); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci return res; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_check_rate_and_errors); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic void ak4113_stats(struct work_struct *work) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct ak4113 *chip = container_of(work, struct ak4113, work.work); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (atomic_inc_return(&chip->wq_processing) == 1) 62062306a36Sopenharmony_ci snd_ak4113_check_rate_and_errors(chip, chip->check_flags); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (atomic_dec_and_test(&chip->wq_processing)) 62362306a36Sopenharmony_ci schedule_delayed_work(&chip->work, HZ / 10); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci#ifdef CONFIG_PM 62762306a36Sopenharmony_civoid snd_ak4113_suspend(struct ak4113 *chip) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci atomic_inc(&chip->wq_processing); /* don't schedule new work */ 63062306a36Sopenharmony_ci cancel_delayed_work_sync(&chip->work); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4113_suspend); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_civoid snd_ak4113_resume(struct ak4113 *chip) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci atomic_dec(&chip->wq_processing); 63762306a36Sopenharmony_ci snd_ak4113_reinit(chip); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ciEXPORT_SYMBOL(snd_ak4113_resume); 64062306a36Sopenharmony_ci#endif 641