18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Routines for control of the AK4113 via I2C/4-wire serial interface 48c2ecf20Sopenharmony_ci * IEC958 (S/PDIF) receiver by Asahi Kasei 58c2ecf20Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 68c2ecf20Sopenharmony_ci * Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <sound/core.h> 138c2ecf20Sopenharmony_ci#include <sound/control.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm.h> 158c2ecf20Sopenharmony_ci#include <sound/ak4113.h> 168c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 178c2ecf20Sopenharmony_ci#include <sound/info.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Pavel Hofman <pavel.hofman@ivitera.com>"); 208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AK4113 IEC958 (S/PDIF) receiver by Asahi Kasei"); 218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define AK4113_ADDR 0x00 /* fixed address */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void ak4113_stats(struct work_struct *work); 268c2ecf20Sopenharmony_cistatic void ak4113_init_regs(struct ak4113 *chip); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void reg_write(struct ak4113 *ak4113, unsigned char reg, 308c2ecf20Sopenharmony_ci unsigned char val) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci ak4113->write(ak4113->private_data, reg, val); 338c2ecf20Sopenharmony_ci if (reg < sizeof(ak4113->regmap)) 348c2ecf20Sopenharmony_ci ak4113->regmap[reg] = val; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return ak4113->read(ak4113->private_data, reg); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void snd_ak4113_free(struct ak4113 *chip) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci atomic_inc(&chip->wq_processing); /* don't schedule new work */ 458c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&chip->work); 468c2ecf20Sopenharmony_ci kfree(chip); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int snd_ak4113_dev_free(struct snd_device *device) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct ak4113 *chip = device->device_data; 528c2ecf20Sopenharmony_ci snd_ak4113_free(chip); 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciint snd_ak4113_create(struct snd_card *card, ak4113_read_t *read, 578c2ecf20Sopenharmony_ci ak4113_write_t *write, const unsigned char *pgm, 588c2ecf20Sopenharmony_ci void *private_data, struct ak4113 **r_ak4113) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct ak4113 *chip; 618c2ecf20Sopenharmony_ci int err; 628c2ecf20Sopenharmony_ci unsigned char reg; 638c2ecf20Sopenharmony_ci static const struct snd_device_ops ops = { 648c2ecf20Sopenharmony_ci .dev_free = snd_ak4113_dev_free, 658c2ecf20Sopenharmony_ci }; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 688c2ecf20Sopenharmony_ci if (chip == NULL) 698c2ecf20Sopenharmony_ci return -ENOMEM; 708c2ecf20Sopenharmony_ci spin_lock_init(&chip->lock); 718c2ecf20Sopenharmony_ci chip->card = card; 728c2ecf20Sopenharmony_ci chip->read = read; 738c2ecf20Sopenharmony_ci chip->write = write; 748c2ecf20Sopenharmony_ci chip->private_data = private_data; 758c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&chip->work, ak4113_stats); 768c2ecf20Sopenharmony_ci atomic_set(&chip->wq_processing, 0); 778c2ecf20Sopenharmony_ci mutex_init(&chip->reinit_mutex); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) 808c2ecf20Sopenharmony_ci chip->regmap[reg] = pgm[reg]; 818c2ecf20Sopenharmony_ci ak4113_init_regs(chip); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci chip->rcs0 = reg_read(chip, AK4113_REG_RCS0) & ~(AK4113_QINT | 848c2ecf20Sopenharmony_ci AK4113_CINT | AK4113_STC); 858c2ecf20Sopenharmony_ci chip->rcs1 = reg_read(chip, AK4113_REG_RCS1); 868c2ecf20Sopenharmony_ci chip->rcs2 = reg_read(chip, AK4113_REG_RCS2); 878c2ecf20Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops); 888c2ecf20Sopenharmony_ci if (err < 0) 898c2ecf20Sopenharmony_ci goto __fail; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (r_ak4113) 928c2ecf20Sopenharmony_ci *r_ak4113 = chip; 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci__fail: 968c2ecf20Sopenharmony_ci snd_ak4113_free(chip); 978c2ecf20Sopenharmony_ci return err; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_create); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid snd_ak4113_reg_write(struct ak4113 *chip, unsigned char reg, 1028c2ecf20Sopenharmony_ci unsigned char mask, unsigned char val) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci if (reg >= AK4113_WRITABLE_REGS) 1058c2ecf20Sopenharmony_ci return; 1068c2ecf20Sopenharmony_ci reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_reg_write); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void ak4113_init_regs(struct ak4113 *chip) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci unsigned char old = chip->regmap[AK4113_REG_PWRDN], reg; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* bring the chip to reset state and powerdown state */ 1158c2ecf20Sopenharmony_ci reg_write(chip, AK4113_REG_PWRDN, old & ~(AK4113_RST|AK4113_PWN)); 1168c2ecf20Sopenharmony_ci udelay(200); 1178c2ecf20Sopenharmony_ci /* release reset, but leave powerdown */ 1188c2ecf20Sopenharmony_ci reg_write(chip, AK4113_REG_PWRDN, (old | AK4113_RST) & ~AK4113_PWN); 1198c2ecf20Sopenharmony_ci udelay(200); 1208c2ecf20Sopenharmony_ci for (reg = 1; reg < AK4113_WRITABLE_REGS; reg++) 1218c2ecf20Sopenharmony_ci reg_write(chip, reg, chip->regmap[reg]); 1228c2ecf20Sopenharmony_ci /* release powerdown, everything is initialized now */ 1238c2ecf20Sopenharmony_ci reg_write(chip, AK4113_REG_PWRDN, old | AK4113_RST | AK4113_PWN); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_civoid snd_ak4113_reinit(struct ak4113 *chip) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci if (atomic_inc_return(&chip->wq_processing) == 1) 1298c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&chip->work); 1308c2ecf20Sopenharmony_ci mutex_lock(&chip->reinit_mutex); 1318c2ecf20Sopenharmony_ci ak4113_init_regs(chip); 1328c2ecf20Sopenharmony_ci mutex_unlock(&chip->reinit_mutex); 1338c2ecf20Sopenharmony_ci /* bring up statistics / event queing */ 1348c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&chip->wq_processing)) 1358c2ecf20Sopenharmony_ci schedule_delayed_work(&chip->work, HZ / 10); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_reinit); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic unsigned int external_rate(unsigned char rcs1) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci switch (rcs1 & (AK4113_FS0|AK4113_FS1|AK4113_FS2|AK4113_FS3)) { 1428c2ecf20Sopenharmony_ci case AK4113_FS_8000HZ: 1438c2ecf20Sopenharmony_ci return 8000; 1448c2ecf20Sopenharmony_ci case AK4113_FS_11025HZ: 1458c2ecf20Sopenharmony_ci return 11025; 1468c2ecf20Sopenharmony_ci case AK4113_FS_16000HZ: 1478c2ecf20Sopenharmony_ci return 16000; 1488c2ecf20Sopenharmony_ci case AK4113_FS_22050HZ: 1498c2ecf20Sopenharmony_ci return 22050; 1508c2ecf20Sopenharmony_ci case AK4113_FS_24000HZ: 1518c2ecf20Sopenharmony_ci return 24000; 1528c2ecf20Sopenharmony_ci case AK4113_FS_32000HZ: 1538c2ecf20Sopenharmony_ci return 32000; 1548c2ecf20Sopenharmony_ci case AK4113_FS_44100HZ: 1558c2ecf20Sopenharmony_ci return 44100; 1568c2ecf20Sopenharmony_ci case AK4113_FS_48000HZ: 1578c2ecf20Sopenharmony_ci return 48000; 1588c2ecf20Sopenharmony_ci case AK4113_FS_64000HZ: 1598c2ecf20Sopenharmony_ci return 64000; 1608c2ecf20Sopenharmony_ci case AK4113_FS_88200HZ: 1618c2ecf20Sopenharmony_ci return 88200; 1628c2ecf20Sopenharmony_ci case AK4113_FS_96000HZ: 1638c2ecf20Sopenharmony_ci return 96000; 1648c2ecf20Sopenharmony_ci case AK4113_FS_176400HZ: 1658c2ecf20Sopenharmony_ci return 176400; 1668c2ecf20Sopenharmony_ci case AK4113_FS_192000HZ: 1678c2ecf20Sopenharmony_ci return 192000; 1688c2ecf20Sopenharmony_ci default: 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int snd_ak4113_in_error_info(struct snd_kcontrol *kcontrol, 1748c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1778c2ecf20Sopenharmony_ci uinfo->count = 1; 1788c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 1798c2ecf20Sopenharmony_ci uinfo->value.integer.max = LONG_MAX; 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol, 1848c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci spin_lock_irq(&chip->lock); 1898c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 1908c2ecf20Sopenharmony_ci chip->errors[kcontrol->private_value]; 1918c2ecf20Sopenharmony_ci chip->errors[kcontrol->private_value] = 0; 1928c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->lock); 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#define snd_ak4113_in_bit_info snd_ctl_boolean_mono_info 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int snd_ak4113_in_bit_get(struct snd_kcontrol *kcontrol, 1998c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 2028c2ecf20Sopenharmony_ci unsigned char reg = kcontrol->private_value & 0xff; 2038c2ecf20Sopenharmony_ci unsigned char bit = (kcontrol->private_value >> 8) & 0xff; 2048c2ecf20Sopenharmony_ci unsigned char inv = (kcontrol->private_value >> 31) & 1; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 2078c2ecf20Sopenharmony_ci ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int snd_ak4113_rx_info(struct snd_kcontrol *kcontrol, 2128c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2158c2ecf20Sopenharmony_ci uinfo->count = 1; 2168c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 2178c2ecf20Sopenharmony_ci uinfo->value.integer.max = 5; 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int snd_ak4113_rx_get(struct snd_kcontrol *kcontrol, 2228c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 2278c2ecf20Sopenharmony_ci (AK4113_IPS(chip->regmap[AK4113_REG_IO1])); 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol, 2328c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 2358c2ecf20Sopenharmony_ci int change; 2368c2ecf20Sopenharmony_ci u8 old_val; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci spin_lock_irq(&chip->lock); 2398c2ecf20Sopenharmony_ci old_val = chip->regmap[AK4113_REG_IO1]; 2408c2ecf20Sopenharmony_ci change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val); 2418c2ecf20Sopenharmony_ci if (change) 2428c2ecf20Sopenharmony_ci reg_write(chip, AK4113_REG_IO1, 2438c2ecf20Sopenharmony_ci (old_val & (~AK4113_IPS(0xff))) | 2448c2ecf20Sopenharmony_ci (AK4113_IPS(ucontrol->value.integer.value[0]))); 2458c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->lock); 2468c2ecf20Sopenharmony_ci return change; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int snd_ak4113_rate_info(struct snd_kcontrol *kcontrol, 2508c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2538c2ecf20Sopenharmony_ci uinfo->count = 1; 2548c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 2558c2ecf20Sopenharmony_ci uinfo->value.integer.max = 192000; 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int snd_ak4113_rate_get(struct snd_kcontrol *kcontrol, 2608c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = external_rate(reg_read(chip, 2658c2ecf20Sopenharmony_ci AK4113_REG_RCS1)); 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_info(struct snd_kcontrol *kcontrol, 2708c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 2738c2ecf20Sopenharmony_ci uinfo->count = 1; 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_get(struct snd_kcontrol *kcontrol, 2788c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 2818c2ecf20Sopenharmony_ci unsigned i; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci for (i = 0; i < AK4113_REG_RXCSB_SIZE; i++) 2848c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[i] = reg_read(chip, 2858c2ecf20Sopenharmony_ci AK4113_REG_RXCSB0 + i); 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_mask_info(struct snd_kcontrol *kcontrol, 2908c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 2938c2ecf20Sopenharmony_ci uinfo->count = 1; 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_mask_get(struct snd_kcontrol *kcontrol, 2988c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci memset(ucontrol->value.iec958.status, 0xff, AK4113_REG_RXCSB_SIZE); 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_pinfo(struct snd_kcontrol *kcontrol, 3058c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3088c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 3098c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0xffff; 3108c2ecf20Sopenharmony_ci uinfo->count = 4; 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_pget(struct snd_kcontrol *kcontrol, 3158c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 3188c2ecf20Sopenharmony_ci unsigned short tmp; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 0xf8f2; 3218c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = 0x4e1f; 3228c2ecf20Sopenharmony_ci tmp = reg_read(chip, AK4113_REG_Pc0) | 3238c2ecf20Sopenharmony_ci (reg_read(chip, AK4113_REG_Pc1) << 8); 3248c2ecf20Sopenharmony_ci ucontrol->value.integer.value[2] = tmp; 3258c2ecf20Sopenharmony_ci tmp = reg_read(chip, AK4113_REG_Pd0) | 3268c2ecf20Sopenharmony_ci (reg_read(chip, AK4113_REG_Pd1) << 8); 3278c2ecf20Sopenharmony_ci ucontrol->value.integer.value[3] = tmp; 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_qinfo(struct snd_kcontrol *kcontrol, 3328c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 3358c2ecf20Sopenharmony_ci uinfo->count = AK4113_REG_QSUB_SIZE; 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int snd_ak4113_spdif_qget(struct snd_kcontrol *kcontrol, 3408c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct ak4113 *chip = snd_kcontrol_chip(kcontrol); 3438c2ecf20Sopenharmony_ci unsigned i; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci for (i = 0; i < AK4113_REG_QSUB_SIZE; i++) 3468c2ecf20Sopenharmony_ci ucontrol->value.bytes.data[i] = reg_read(chip, 3478c2ecf20Sopenharmony_ci AK4113_REG_QSUB_ADDR + i); 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/* Don't forget to change AK4113_CONTROLS define!!! */ 3528c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3558c2ecf20Sopenharmony_ci .name = "IEC958 Parity Errors", 3568c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 3578c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3588c2ecf20Sopenharmony_ci .info = snd_ak4113_in_error_info, 3598c2ecf20Sopenharmony_ci .get = snd_ak4113_in_error_get, 3608c2ecf20Sopenharmony_ci .private_value = AK4113_PARITY_ERRORS, 3618c2ecf20Sopenharmony_ci}, 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3648c2ecf20Sopenharmony_ci .name = "IEC958 V-Bit Errors", 3658c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 3668c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3678c2ecf20Sopenharmony_ci .info = snd_ak4113_in_error_info, 3688c2ecf20Sopenharmony_ci .get = snd_ak4113_in_error_get, 3698c2ecf20Sopenharmony_ci .private_value = AK4113_V_BIT_ERRORS, 3708c2ecf20Sopenharmony_ci}, 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3738c2ecf20Sopenharmony_ci .name = "IEC958 C-CRC Errors", 3748c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 3758c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3768c2ecf20Sopenharmony_ci .info = snd_ak4113_in_error_info, 3778c2ecf20Sopenharmony_ci .get = snd_ak4113_in_error_get, 3788c2ecf20Sopenharmony_ci .private_value = AK4113_CCRC_ERRORS, 3798c2ecf20Sopenharmony_ci}, 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3828c2ecf20Sopenharmony_ci .name = "IEC958 Q-CRC Errors", 3838c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 3848c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3858c2ecf20Sopenharmony_ci .info = snd_ak4113_in_error_info, 3868c2ecf20Sopenharmony_ci .get = snd_ak4113_in_error_get, 3878c2ecf20Sopenharmony_ci .private_value = AK4113_QCRC_ERRORS, 3888c2ecf20Sopenharmony_ci}, 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3918c2ecf20Sopenharmony_ci .name = "IEC958 External Rate", 3928c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 3938c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3948c2ecf20Sopenharmony_ci .info = snd_ak4113_rate_info, 3958c2ecf20Sopenharmony_ci .get = snd_ak4113_rate_get, 3968c2ecf20Sopenharmony_ci}, 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3998c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), 4008c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 4018c2ecf20Sopenharmony_ci .info = snd_ak4113_spdif_mask_info, 4028c2ecf20Sopenharmony_ci .get = snd_ak4113_spdif_mask_get, 4038c2ecf20Sopenharmony_ci}, 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4068c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 4078c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 4088c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4098c2ecf20Sopenharmony_ci .info = snd_ak4113_spdif_info, 4108c2ecf20Sopenharmony_ci .get = snd_ak4113_spdif_get, 4118c2ecf20Sopenharmony_ci}, 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4148c2ecf20Sopenharmony_ci .name = "IEC958 Preamble Capture Default", 4158c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 4168c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4178c2ecf20Sopenharmony_ci .info = snd_ak4113_spdif_pinfo, 4188c2ecf20Sopenharmony_ci .get = snd_ak4113_spdif_pget, 4198c2ecf20Sopenharmony_ci}, 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4228c2ecf20Sopenharmony_ci .name = "IEC958 Q-subcode Capture Default", 4238c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 4248c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4258c2ecf20Sopenharmony_ci .info = snd_ak4113_spdif_qinfo, 4268c2ecf20Sopenharmony_ci .get = snd_ak4113_spdif_qget, 4278c2ecf20Sopenharmony_ci}, 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4308c2ecf20Sopenharmony_ci .name = "IEC958 Audio", 4318c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 4328c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4338c2ecf20Sopenharmony_ci .info = snd_ak4113_in_bit_info, 4348c2ecf20Sopenharmony_ci .get = snd_ak4113_in_bit_get, 4358c2ecf20Sopenharmony_ci .private_value = (1<<31) | (1<<8) | AK4113_REG_RCS0, 4368c2ecf20Sopenharmony_ci}, 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4398c2ecf20Sopenharmony_ci .name = "IEC958 Non-PCM Bitstream", 4408c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 4418c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4428c2ecf20Sopenharmony_ci .info = snd_ak4113_in_bit_info, 4438c2ecf20Sopenharmony_ci .get = snd_ak4113_in_bit_get, 4448c2ecf20Sopenharmony_ci .private_value = (0<<8) | AK4113_REG_RCS1, 4458c2ecf20Sopenharmony_ci}, 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4488c2ecf20Sopenharmony_ci .name = "IEC958 DTS Bitstream", 4498c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 4508c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4518c2ecf20Sopenharmony_ci .info = snd_ak4113_in_bit_info, 4528c2ecf20Sopenharmony_ci .get = snd_ak4113_in_bit_get, 4538c2ecf20Sopenharmony_ci .private_value = (1<<8) | AK4113_REG_RCS1, 4548c2ecf20Sopenharmony_ci}, 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4578c2ecf20Sopenharmony_ci .name = "AK4113 Input Select", 4588c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 4598c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_WRITE, 4608c2ecf20Sopenharmony_ci .info = snd_ak4113_rx_info, 4618c2ecf20Sopenharmony_ci .get = snd_ak4113_rx_get, 4628c2ecf20Sopenharmony_ci .put = snd_ak4113_rx_put, 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci}; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic void snd_ak4113_proc_regs_read(struct snd_info_entry *entry, 4678c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct ak4113 *ak4113 = entry->private_data; 4708c2ecf20Sopenharmony_ci int reg, val; 4718c2ecf20Sopenharmony_ci /* all ak4113 registers 0x00 - 0x1c */ 4728c2ecf20Sopenharmony_ci for (reg = 0; reg < 0x1d; reg++) { 4738c2ecf20Sopenharmony_ci val = reg_read(ak4113, reg); 4748c2ecf20Sopenharmony_ci snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic void snd_ak4113_proc_init(struct ak4113 *ak4113) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci snd_card_ro_proc_new(ak4113->card, "ak4113", ak4113, 4818c2ecf20Sopenharmony_ci snd_ak4113_proc_regs_read); 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ciint snd_ak4113_build(struct ak4113 *ak4113, 4858c2ecf20Sopenharmony_ci struct snd_pcm_substream *cap_substream) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 4888c2ecf20Sopenharmony_ci unsigned int idx; 4898c2ecf20Sopenharmony_ci int err; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (snd_BUG_ON(!cap_substream)) 4928c2ecf20Sopenharmony_ci return -EINVAL; 4938c2ecf20Sopenharmony_ci ak4113->substream = cap_substream; 4948c2ecf20Sopenharmony_ci for (idx = 0; idx < AK4113_CONTROLS; idx++) { 4958c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(&snd_ak4113_iec958_controls[idx], ak4113); 4968c2ecf20Sopenharmony_ci if (kctl == NULL) 4978c2ecf20Sopenharmony_ci return -ENOMEM; 4988c2ecf20Sopenharmony_ci kctl->id.device = cap_substream->pcm->device; 4998c2ecf20Sopenharmony_ci kctl->id.subdevice = cap_substream->number; 5008c2ecf20Sopenharmony_ci err = snd_ctl_add(ak4113->card, kctl); 5018c2ecf20Sopenharmony_ci if (err < 0) 5028c2ecf20Sopenharmony_ci return err; 5038c2ecf20Sopenharmony_ci ak4113->kctls[idx] = kctl; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci snd_ak4113_proc_init(ak4113); 5068c2ecf20Sopenharmony_ci /* trigger workq */ 5078c2ecf20Sopenharmony_ci schedule_delayed_work(&ak4113->work, HZ / 10); 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_build); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ciint snd_ak4113_external_rate(struct ak4113 *ak4113) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci unsigned char rcs1; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci rcs1 = reg_read(ak4113, AK4113_REG_RCS1); 5178c2ecf20Sopenharmony_ci return external_rate(rcs1); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_external_rate); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ciint snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = 5248c2ecf20Sopenharmony_ci ak4113->substream ? ak4113->substream->runtime : NULL; 5258c2ecf20Sopenharmony_ci unsigned long _flags; 5268c2ecf20Sopenharmony_ci int res = 0; 5278c2ecf20Sopenharmony_ci unsigned char rcs0, rcs1, rcs2; 5288c2ecf20Sopenharmony_ci unsigned char c0, c1; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci rcs1 = reg_read(ak4113, AK4113_REG_RCS1); 5318c2ecf20Sopenharmony_ci if (flags & AK4113_CHECK_NO_STAT) 5328c2ecf20Sopenharmony_ci goto __rate; 5338c2ecf20Sopenharmony_ci rcs0 = reg_read(ak4113, AK4113_REG_RCS0); 5348c2ecf20Sopenharmony_ci rcs2 = reg_read(ak4113, AK4113_REG_RCS2); 5358c2ecf20Sopenharmony_ci spin_lock_irqsave(&ak4113->lock, _flags); 5368c2ecf20Sopenharmony_ci if (rcs0 & AK4113_PAR) 5378c2ecf20Sopenharmony_ci ak4113->errors[AK4113_PARITY_ERRORS]++; 5388c2ecf20Sopenharmony_ci if (rcs0 & AK4113_V) 5398c2ecf20Sopenharmony_ci ak4113->errors[AK4113_V_BIT_ERRORS]++; 5408c2ecf20Sopenharmony_ci if (rcs2 & AK4113_CCRC) 5418c2ecf20Sopenharmony_ci ak4113->errors[AK4113_CCRC_ERRORS]++; 5428c2ecf20Sopenharmony_ci if (rcs2 & AK4113_QCRC) 5438c2ecf20Sopenharmony_ci ak4113->errors[AK4113_QCRC_ERRORS]++; 5448c2ecf20Sopenharmony_ci c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | 5458c2ecf20Sopenharmony_ci AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^ 5468c2ecf20Sopenharmony_ci (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | 5478c2ecf20Sopenharmony_ci AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)); 5488c2ecf20Sopenharmony_ci c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | 5498c2ecf20Sopenharmony_ci AK4113_DAT | 0xf0)) ^ 5508c2ecf20Sopenharmony_ci (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | 5518c2ecf20Sopenharmony_ci AK4113_DAT | 0xf0)); 5528c2ecf20Sopenharmony_ci ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC); 5538c2ecf20Sopenharmony_ci ak4113->rcs1 = rcs1; 5548c2ecf20Sopenharmony_ci ak4113->rcs2 = rcs2; 5558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ak4113->lock, _flags); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (rcs0 & AK4113_PAR) 5588c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5598c2ecf20Sopenharmony_ci &ak4113->kctls[0]->id); 5608c2ecf20Sopenharmony_ci if (rcs0 & AK4113_V) 5618c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5628c2ecf20Sopenharmony_ci &ak4113->kctls[1]->id); 5638c2ecf20Sopenharmony_ci if (rcs2 & AK4113_CCRC) 5648c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5658c2ecf20Sopenharmony_ci &ak4113->kctls[2]->id); 5668c2ecf20Sopenharmony_ci if (rcs2 & AK4113_QCRC) 5678c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5688c2ecf20Sopenharmony_ci &ak4113->kctls[3]->id); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* rate change */ 5718c2ecf20Sopenharmony_ci if (c1 & 0xf0) 5728c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5738c2ecf20Sopenharmony_ci &ak4113->kctls[4]->id); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if ((c1 & AK4113_PEM) | (c0 & AK4113_CINT)) 5768c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5778c2ecf20Sopenharmony_ci &ak4113->kctls[6]->id); 5788c2ecf20Sopenharmony_ci if (c0 & AK4113_QINT) 5798c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5808c2ecf20Sopenharmony_ci &ak4113->kctls[8]->id); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (c0 & AK4113_AUDION) 5838c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5848c2ecf20Sopenharmony_ci &ak4113->kctls[9]->id); 5858c2ecf20Sopenharmony_ci if (c1 & AK4113_NPCM) 5868c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5878c2ecf20Sopenharmony_ci &ak4113->kctls[10]->id); 5888c2ecf20Sopenharmony_ci if (c1 & AK4113_DTSCD) 5898c2ecf20Sopenharmony_ci snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, 5908c2ecf20Sopenharmony_ci &ak4113->kctls[11]->id); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (ak4113->change_callback && (c0 | c1) != 0) 5938c2ecf20Sopenharmony_ci ak4113->change_callback(ak4113, c0, c1); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci__rate: 5968c2ecf20Sopenharmony_ci /* compare rate */ 5978c2ecf20Sopenharmony_ci res = external_rate(rcs1); 5988c2ecf20Sopenharmony_ci if (!(flags & AK4113_CHECK_NO_RATE) && runtime && 5998c2ecf20Sopenharmony_ci (runtime->rate != res)) { 6008c2ecf20Sopenharmony_ci snd_pcm_stream_lock_irqsave(ak4113->substream, _flags); 6018c2ecf20Sopenharmony_ci if (snd_pcm_running(ak4113->substream)) { 6028c2ecf20Sopenharmony_ci /*printk(KERN_DEBUG "rate changed (%i <- %i)\n", 6038c2ecf20Sopenharmony_ci * runtime->rate, res); */ 6048c2ecf20Sopenharmony_ci snd_pcm_stop(ak4113->substream, 6058c2ecf20Sopenharmony_ci SNDRV_PCM_STATE_DRAINING); 6068c2ecf20Sopenharmony_ci wake_up(&runtime->sleep); 6078c2ecf20Sopenharmony_ci res = 1; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci snd_pcm_stream_unlock_irqrestore(ak4113->substream, _flags); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci return res; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_ak4113_check_rate_and_errors); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic void ak4113_stats(struct work_struct *work) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct ak4113 *chip = container_of(work, struct ak4113, work.work); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (atomic_inc_return(&chip->wq_processing) == 1) 6208c2ecf20Sopenharmony_ci snd_ak4113_check_rate_and_errors(chip, chip->check_flags); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&chip->wq_processing)) 6238c2ecf20Sopenharmony_ci schedule_delayed_work(&chip->work, HZ / 10); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6278c2ecf20Sopenharmony_civoid snd_ak4113_suspend(struct ak4113 *chip) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci atomic_inc(&chip->wq_processing); /* don't schedule new work */ 6308c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&chip->work); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4113_suspend); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_civoid snd_ak4113_resume(struct ak4113 *chip) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci atomic_dec(&chip->wq_processing); 6378c2ecf20Sopenharmony_ci snd_ak4113_reinit(chip); 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4113_resume); 6408c2ecf20Sopenharmony_ci#endif 641