18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Routines for control of the AK4117 via 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 */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <sound/core.h> 128c2ecf20Sopenharmony_ci#include <sound/control.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm.h> 148c2ecf20Sopenharmony_ci#include <sound/ak4117.h> 158c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei"); 198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define AK4117_ADDR 0x00 /* fixed address */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void snd_ak4117_timer(struct timer_list *t); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char val) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci ak4117->write(ak4117->private_data, reg, val); 288c2ecf20Sopenharmony_ci if (reg < sizeof(ak4117->regmap)) 298c2ecf20Sopenharmony_ci ak4117->regmap[reg] = val; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline unsigned char reg_read(struct ak4117 *ak4117, unsigned char reg) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return ak4117->read(ak4117->private_data, reg); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#if 0 388c2ecf20Sopenharmony_cistatic void reg_dump(struct ak4117 *ak4117) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int i; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci printk(KERN_DEBUG "AK4117 REG DUMP:\n"); 438c2ecf20Sopenharmony_ci for (i = 0; i < 0x1b; i++) 448c2ecf20Sopenharmony_ci printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci#endif 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void snd_ak4117_free(struct ak4117 *chip) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci del_timer_sync(&chip->timer); 518c2ecf20Sopenharmony_ci kfree(chip); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int snd_ak4117_dev_free(struct snd_device *device) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct ak4117 *chip = device->device_data; 578c2ecf20Sopenharmony_ci snd_ak4117_free(chip); 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciint snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, 628c2ecf20Sopenharmony_ci const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct ak4117 *chip; 658c2ecf20Sopenharmony_ci int err = 0; 668c2ecf20Sopenharmony_ci unsigned char reg; 678c2ecf20Sopenharmony_ci static const struct snd_device_ops ops = { 688c2ecf20Sopenharmony_ci .dev_free = snd_ak4117_dev_free, 698c2ecf20Sopenharmony_ci }; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 728c2ecf20Sopenharmony_ci if (chip == NULL) 738c2ecf20Sopenharmony_ci return -ENOMEM; 748c2ecf20Sopenharmony_ci spin_lock_init(&chip->lock); 758c2ecf20Sopenharmony_ci chip->card = card; 768c2ecf20Sopenharmony_ci chip->read = read; 778c2ecf20Sopenharmony_ci chip->write = write; 788c2ecf20Sopenharmony_ci chip->private_data = private_data; 798c2ecf20Sopenharmony_ci timer_setup(&chip->timer, snd_ak4117_timer, 0); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci for (reg = 0; reg < 5; reg++) 828c2ecf20Sopenharmony_ci chip->regmap[reg] = pgm[reg]; 838c2ecf20Sopenharmony_ci snd_ak4117_reinit(chip); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci chip->rcs0 = reg_read(chip, AK4117_REG_RCS0) & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); 868c2ecf20Sopenharmony_ci chip->rcs1 = reg_read(chip, AK4117_REG_RCS1); 878c2ecf20Sopenharmony_ci chip->rcs2 = reg_read(chip, AK4117_REG_RCS2); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if ((err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops)) < 0) 908c2ecf20Sopenharmony_ci goto __fail; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (r_ak4117) 938c2ecf20Sopenharmony_ci *r_ak4117 = chip; 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci __fail: 978c2ecf20Sopenharmony_ci snd_ak4117_free(chip); 988c2ecf20Sopenharmony_ci return err; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci if (reg >= 5) 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_civoid snd_ak4117_reinit(struct ak4117 *chip) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci del_timer(&chip->timer); 1138c2ecf20Sopenharmony_ci chip->init = 1; 1148c2ecf20Sopenharmony_ci /* bring the chip to reset state and powerdown state */ 1158c2ecf20Sopenharmony_ci reg_write(chip, AK4117_REG_PWRDN, 0); 1168c2ecf20Sopenharmony_ci udelay(200); 1178c2ecf20Sopenharmony_ci /* release reset, but leave powerdown */ 1188c2ecf20Sopenharmony_ci reg_write(chip, AK4117_REG_PWRDN, (old | AK4117_RST) & ~AK4117_PWN); 1198c2ecf20Sopenharmony_ci udelay(200); 1208c2ecf20Sopenharmony_ci for (reg = 1; reg < 5; reg++) 1218c2ecf20Sopenharmony_ci reg_write(chip, reg, chip->regmap[reg]); 1228c2ecf20Sopenharmony_ci /* release powerdown, everything is initialized now */ 1238c2ecf20Sopenharmony_ci reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN); 1248c2ecf20Sopenharmony_ci chip->init = 0; 1258c2ecf20Sopenharmony_ci mod_timer(&chip->timer, 1 + jiffies); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic unsigned int external_rate(unsigned char rcs1) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci switch (rcs1 & (AK4117_FS0|AK4117_FS1|AK4117_FS2|AK4117_FS3)) { 1318c2ecf20Sopenharmony_ci case AK4117_FS_32000HZ: return 32000; 1328c2ecf20Sopenharmony_ci case AK4117_FS_44100HZ: return 44100; 1338c2ecf20Sopenharmony_ci case AK4117_FS_48000HZ: return 48000; 1348c2ecf20Sopenharmony_ci case AK4117_FS_88200HZ: return 88200; 1358c2ecf20Sopenharmony_ci case AK4117_FS_96000HZ: return 96000; 1368c2ecf20Sopenharmony_ci case AK4117_FS_176400HZ: return 176400; 1378c2ecf20Sopenharmony_ci case AK4117_FS_192000HZ: return 192000; 1388c2ecf20Sopenharmony_ci default: return 0; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int snd_ak4117_in_error_info(struct snd_kcontrol *kcontrol, 1438c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1468c2ecf20Sopenharmony_ci uinfo->count = 1; 1478c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 1488c2ecf20Sopenharmony_ci uinfo->value.integer.max = LONG_MAX; 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol, 1538c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci spin_lock_irq(&chip->lock); 1588c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 1598c2ecf20Sopenharmony_ci chip->errors[kcontrol->private_value]; 1608c2ecf20Sopenharmony_ci chip->errors[kcontrol->private_value] = 0; 1618c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->lock); 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define snd_ak4117_in_bit_info snd_ctl_boolean_mono_info 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol, 1688c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 1718c2ecf20Sopenharmony_ci unsigned char reg = kcontrol->private_value & 0xff; 1728c2ecf20Sopenharmony_ci unsigned char bit = (kcontrol->private_value >> 8) & 0xff; 1738c2ecf20Sopenharmony_ci unsigned char inv = (kcontrol->private_value >> 31) & 1; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int snd_ak4117_rx_info(struct snd_kcontrol *kcontrol, 1808c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1838c2ecf20Sopenharmony_ci uinfo->count = 1; 1848c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 1858c2ecf20Sopenharmony_ci uinfo->value.integer.max = 1; 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int snd_ak4117_rx_get(struct snd_kcontrol *kcontrol, 1908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0; 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol, 1998c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2028c2ecf20Sopenharmony_ci int change; 2038c2ecf20Sopenharmony_ci u8 old_val; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci spin_lock_irq(&chip->lock); 2068c2ecf20Sopenharmony_ci old_val = chip->regmap[AK4117_REG_IO]; 2078c2ecf20Sopenharmony_ci change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0); 2088c2ecf20Sopenharmony_ci if (change) 2098c2ecf20Sopenharmony_ci reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0)); 2108c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->lock); 2118c2ecf20Sopenharmony_ci return change; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int snd_ak4117_rate_info(struct snd_kcontrol *kcontrol, 2158c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2188c2ecf20Sopenharmony_ci uinfo->count = 1; 2198c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 2208c2ecf20Sopenharmony_ci uinfo->value.integer.max = 192000; 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int snd_ak4117_rate_get(struct snd_kcontrol *kcontrol, 2258c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1)); 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 2368c2ecf20Sopenharmony_ci uinfo->count = 1; 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_get(struct snd_kcontrol *kcontrol, 2418c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2448c2ecf20Sopenharmony_ci unsigned i; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++) 2478c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i); 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 2548c2ecf20Sopenharmony_ci uinfo->count = 1; 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_mask_get(struct snd_kcontrol *kcontrol, 2598c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE); 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_pinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2688c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 2698c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0xffff; 2708c2ecf20Sopenharmony_ci uinfo->count = 4; 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_pget(struct snd_kcontrol *kcontrol, 2758c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2788c2ecf20Sopenharmony_ci unsigned short tmp; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 0xf8f2; 2818c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = 0x4e1f; 2828c2ecf20Sopenharmony_ci tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8); 2838c2ecf20Sopenharmony_ci ucontrol->value.integer.value[2] = tmp; 2848c2ecf20Sopenharmony_ci tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8); 2858c2ecf20Sopenharmony_ci ucontrol->value.integer.value[3] = tmp; 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 2928c2ecf20Sopenharmony_ci uinfo->count = AK4117_REG_QSUB_SIZE; 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int snd_ak4117_spdif_qget(struct snd_kcontrol *kcontrol, 2978c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 3008c2ecf20Sopenharmony_ci unsigned i; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci for (i = 0; i < AK4117_REG_QSUB_SIZE; i++) 3038c2ecf20Sopenharmony_ci ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i); 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* Don't forget to change AK4117_CONTROLS define!!! */ 3088c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ak4117_iec958_controls[] = { 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3118c2ecf20Sopenharmony_ci .name = "IEC958 Parity Errors", 3128c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3138c2ecf20Sopenharmony_ci .info = snd_ak4117_in_error_info, 3148c2ecf20Sopenharmony_ci .get = snd_ak4117_in_error_get, 3158c2ecf20Sopenharmony_ci .private_value = AK4117_PARITY_ERRORS, 3168c2ecf20Sopenharmony_ci}, 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3198c2ecf20Sopenharmony_ci .name = "IEC958 V-Bit Errors", 3208c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3218c2ecf20Sopenharmony_ci .info = snd_ak4117_in_error_info, 3228c2ecf20Sopenharmony_ci .get = snd_ak4117_in_error_get, 3238c2ecf20Sopenharmony_ci .private_value = AK4117_V_BIT_ERRORS, 3248c2ecf20Sopenharmony_ci}, 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3278c2ecf20Sopenharmony_ci .name = "IEC958 C-CRC Errors", 3288c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3298c2ecf20Sopenharmony_ci .info = snd_ak4117_in_error_info, 3308c2ecf20Sopenharmony_ci .get = snd_ak4117_in_error_get, 3318c2ecf20Sopenharmony_ci .private_value = AK4117_CCRC_ERRORS, 3328c2ecf20Sopenharmony_ci}, 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3358c2ecf20Sopenharmony_ci .name = "IEC958 Q-CRC Errors", 3368c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3378c2ecf20Sopenharmony_ci .info = snd_ak4117_in_error_info, 3388c2ecf20Sopenharmony_ci .get = snd_ak4117_in_error_get, 3398c2ecf20Sopenharmony_ci .private_value = AK4117_QCRC_ERRORS, 3408c2ecf20Sopenharmony_ci}, 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3438c2ecf20Sopenharmony_ci .name = "IEC958 External Rate", 3448c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3458c2ecf20Sopenharmony_ci .info = snd_ak4117_rate_info, 3468c2ecf20Sopenharmony_ci .get = snd_ak4117_rate_get, 3478c2ecf20Sopenharmony_ci}, 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3508c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), 3518c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 3528c2ecf20Sopenharmony_ci .info = snd_ak4117_spdif_mask_info, 3538c2ecf20Sopenharmony_ci .get = snd_ak4117_spdif_mask_get, 3548c2ecf20Sopenharmony_ci}, 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3578c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), 3588c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3598c2ecf20Sopenharmony_ci .info = snd_ak4117_spdif_info, 3608c2ecf20Sopenharmony_ci .get = snd_ak4117_spdif_get, 3618c2ecf20Sopenharmony_ci}, 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3648c2ecf20Sopenharmony_ci .name = "IEC958 Preamble Capture Default", 3658c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3668c2ecf20Sopenharmony_ci .info = snd_ak4117_spdif_pinfo, 3678c2ecf20Sopenharmony_ci .get = snd_ak4117_spdif_pget, 3688c2ecf20Sopenharmony_ci}, 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3718c2ecf20Sopenharmony_ci .name = "IEC958 Q-subcode Capture Default", 3728c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3738c2ecf20Sopenharmony_ci .info = snd_ak4117_spdif_qinfo, 3748c2ecf20Sopenharmony_ci .get = snd_ak4117_spdif_qget, 3758c2ecf20Sopenharmony_ci}, 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3788c2ecf20Sopenharmony_ci .name = "IEC958 Audio", 3798c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3808c2ecf20Sopenharmony_ci .info = snd_ak4117_in_bit_info, 3818c2ecf20Sopenharmony_ci .get = snd_ak4117_in_bit_get, 3828c2ecf20Sopenharmony_ci .private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0, 3838c2ecf20Sopenharmony_ci}, 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3868c2ecf20Sopenharmony_ci .name = "IEC958 Non-PCM Bitstream", 3878c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3888c2ecf20Sopenharmony_ci .info = snd_ak4117_in_bit_info, 3898c2ecf20Sopenharmony_ci .get = snd_ak4117_in_bit_get, 3908c2ecf20Sopenharmony_ci .private_value = (5<<8) | AK4117_REG_RCS1, 3918c2ecf20Sopenharmony_ci}, 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3948c2ecf20Sopenharmony_ci .name = "IEC958 DTS Bitstream", 3958c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3968c2ecf20Sopenharmony_ci .info = snd_ak4117_in_bit_info, 3978c2ecf20Sopenharmony_ci .get = snd_ak4117_in_bit_get, 3988c2ecf20Sopenharmony_ci .private_value = (6<<8) | AK4117_REG_RCS1, 3998c2ecf20Sopenharmony_ci}, 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4028c2ecf20Sopenharmony_ci .name = "AK4117 Input Select", 4038c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE, 4048c2ecf20Sopenharmony_ci .info = snd_ak4117_rx_info, 4058c2ecf20Sopenharmony_ci .get = snd_ak4117_rx_get, 4068c2ecf20Sopenharmony_ci .put = snd_ak4117_rx_put, 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci}; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciint snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *cap_substream) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 4138c2ecf20Sopenharmony_ci unsigned int idx; 4148c2ecf20Sopenharmony_ci int err; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (snd_BUG_ON(!cap_substream)) 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci ak4117->substream = cap_substream; 4198c2ecf20Sopenharmony_ci for (idx = 0; idx < AK4117_CONTROLS; idx++) { 4208c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117); 4218c2ecf20Sopenharmony_ci if (kctl == NULL) 4228c2ecf20Sopenharmony_ci return -ENOMEM; 4238c2ecf20Sopenharmony_ci kctl->id.device = cap_substream->pcm->device; 4248c2ecf20Sopenharmony_ci kctl->id.subdevice = cap_substream->number; 4258c2ecf20Sopenharmony_ci err = snd_ctl_add(ak4117->card, kctl); 4268c2ecf20Sopenharmony_ci if (err < 0) 4278c2ecf20Sopenharmony_ci return err; 4288c2ecf20Sopenharmony_ci ak4117->kctls[idx] = kctl; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ciint snd_ak4117_external_rate(struct ak4117 *ak4117) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci unsigned char rcs1; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci rcs1 = reg_read(ak4117, AK4117_REG_RCS1); 4388c2ecf20Sopenharmony_ci return external_rate(rcs1); 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciint snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = ak4117->substream ? ak4117->substream->runtime : NULL; 4448c2ecf20Sopenharmony_ci unsigned long _flags; 4458c2ecf20Sopenharmony_ci int res = 0; 4468c2ecf20Sopenharmony_ci unsigned char rcs0, rcs1, rcs2; 4478c2ecf20Sopenharmony_ci unsigned char c0, c1; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci rcs1 = reg_read(ak4117, AK4117_REG_RCS1); 4508c2ecf20Sopenharmony_ci if (flags & AK4117_CHECK_NO_STAT) 4518c2ecf20Sopenharmony_ci goto __rate; 4528c2ecf20Sopenharmony_ci rcs0 = reg_read(ak4117, AK4117_REG_RCS0); 4538c2ecf20Sopenharmony_ci rcs2 = reg_read(ak4117, AK4117_REG_RCS2); 4548c2ecf20Sopenharmony_ci // printk(KERN_DEBUG "AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2); 4558c2ecf20Sopenharmony_ci spin_lock_irqsave(&ak4117->lock, _flags); 4568c2ecf20Sopenharmony_ci if (rcs0 & AK4117_PAR) 4578c2ecf20Sopenharmony_ci ak4117->errors[AK4117_PARITY_ERRORS]++; 4588c2ecf20Sopenharmony_ci if (rcs0 & AK4117_V) 4598c2ecf20Sopenharmony_ci ak4117->errors[AK4117_V_BIT_ERRORS]++; 4608c2ecf20Sopenharmony_ci if (rcs2 & AK4117_CCRC) 4618c2ecf20Sopenharmony_ci ak4117->errors[AK4117_CCRC_ERRORS]++; 4628c2ecf20Sopenharmony_ci if (rcs2 & AK4117_QCRC) 4638c2ecf20Sopenharmony_ci ak4117->errors[AK4117_QCRC_ERRORS]++; 4648c2ecf20Sopenharmony_ci c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^ 4658c2ecf20Sopenharmony_ci (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)); 4668c2ecf20Sopenharmony_ci c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^ 4678c2ecf20Sopenharmony_ci (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)); 4688c2ecf20Sopenharmony_ci ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); 4698c2ecf20Sopenharmony_ci ak4117->rcs1 = rcs1; 4708c2ecf20Sopenharmony_ci ak4117->rcs2 = rcs2; 4718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ak4117->lock, _flags); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (rcs0 & AK4117_PAR) 4748c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id); 4758c2ecf20Sopenharmony_ci if (rcs0 & AK4117_V) 4768c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id); 4778c2ecf20Sopenharmony_ci if (rcs2 & AK4117_CCRC) 4788c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id); 4798c2ecf20Sopenharmony_ci if (rcs2 & AK4117_QCRC) 4808c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* rate change */ 4838c2ecf20Sopenharmony_ci if (c1 & 0x0f) 4848c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT)) 4878c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id); 4888c2ecf20Sopenharmony_ci if (c0 & AK4117_QINT) 4898c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (c0 & AK4117_AUDION) 4928c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id); 4938c2ecf20Sopenharmony_ci if (c1 & AK4117_NPCM) 4948c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id); 4958c2ecf20Sopenharmony_ci if (c1 & AK4117_DTSCD) 4968c2ecf20Sopenharmony_ci snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (ak4117->change_callback && (c0 | c1) != 0) 4998c2ecf20Sopenharmony_ci ak4117->change_callback(ak4117, c0, c1); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci __rate: 5028c2ecf20Sopenharmony_ci /* compare rate */ 5038c2ecf20Sopenharmony_ci res = external_rate(rcs1); 5048c2ecf20Sopenharmony_ci if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) { 5058c2ecf20Sopenharmony_ci snd_pcm_stream_lock_irqsave(ak4117->substream, _flags); 5068c2ecf20Sopenharmony_ci if (snd_pcm_running(ak4117->substream)) { 5078c2ecf20Sopenharmony_ci // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res); 5088c2ecf20Sopenharmony_ci snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING); 5098c2ecf20Sopenharmony_ci wake_up(&runtime->sleep); 5108c2ecf20Sopenharmony_ci res = 1; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci return res; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic void snd_ak4117_timer(struct timer_list *t) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct ak4117 *chip = from_timer(chip, t, timer); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (chip->init) 5228c2ecf20Sopenharmony_ci return; 5238c2ecf20Sopenharmony_ci snd_ak4117_check_rate_and_errors(chip, 0); 5248c2ecf20Sopenharmony_ci mod_timer(&chip->timer, 1 + jiffies); 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_create); 5288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_reg_write); 5298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_reinit); 5308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_build); 5318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_external_rate); 5328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_ak4117_check_rate_and_errors); 533