11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Routines for control of the AK4117 via 4-wire serial interface 31da177e4SLinus Torvalds * IEC958 (S/PDIF) receiver by Asahi Kasei 41da177e4SLinus Torvalds * Copyright (c) by Jaroslav Kysela <perex@suse.cz> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 81da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 91da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 101da177e4SLinus Torvalds * (at your option) any later version. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 131da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 141da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 151da177e4SLinus Torvalds * GNU General Public License for more details. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 181da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 191da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <sound/driver.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 251da177e4SLinus Torvalds #include <linux/delay.h> 261da177e4SLinus Torvalds #include <sound/core.h> 271da177e4SLinus Torvalds #include <sound/control.h> 281da177e4SLinus Torvalds #include <sound/pcm.h> 291da177e4SLinus Torvalds #include <sound/ak4117.h> 301da177e4SLinus Torvalds #include <sound/asoundef.h> 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 331da177e4SLinus Torvalds MODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei"); 341da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #define AK4117_ADDR 0x00 /* fixed address */ 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static void snd_ak4117_timer(unsigned long data); 391da177e4SLinus Torvalds 4097f02e05STakashi Iwai static void reg_write(struct ak4117 *ak4117, unsigned char reg, unsigned char val) 411da177e4SLinus Torvalds { 421da177e4SLinus Torvalds ak4117->write(ak4117->private_data, reg, val); 431da177e4SLinus Torvalds if (reg < sizeof(ak4117->regmap)) 441da177e4SLinus Torvalds ak4117->regmap[reg] = val; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 4797f02e05STakashi Iwai static inline unsigned char reg_read(struct ak4117 *ak4117, unsigned char reg) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds return ak4117->read(ak4117->private_data, reg); 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds #if 0 5397f02e05STakashi Iwai static void reg_dump(struct ak4117 *ak4117) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds int i; 561da177e4SLinus Torvalds 5799b359baSTakashi Iwai printk(KERN_DEBUG "AK4117 REG DUMP:\n"); 581da177e4SLinus Torvalds for (i = 0; i < 0x1b; i++) 5999b359baSTakashi Iwai printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0); 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds #endif 621da177e4SLinus Torvalds 6397f02e05STakashi Iwai static void snd_ak4117_free(struct ak4117 *chip) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds del_timer(&chip->timer); 661da177e4SLinus Torvalds kfree(chip); 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 6997f02e05STakashi Iwai static int snd_ak4117_dev_free(struct snd_device *device) 701da177e4SLinus Torvalds { 7197f02e05STakashi Iwai struct ak4117 *chip = device->device_data; 721da177e4SLinus Torvalds snd_ak4117_free(chip); 731da177e4SLinus Torvalds return 0; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 7697f02e05STakashi Iwai int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, 77517400cbSTakashi Iwai const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) 781da177e4SLinus Torvalds { 7997f02e05STakashi Iwai struct ak4117 *chip; 801da177e4SLinus Torvalds int err = 0; 811da177e4SLinus Torvalds unsigned char reg; 8297f02e05STakashi Iwai static struct snd_device_ops ops = { 831da177e4SLinus Torvalds .dev_free = snd_ak4117_dev_free, 841da177e4SLinus Torvalds }; 851da177e4SLinus Torvalds 86561b220aSTakashi Iwai chip = kzalloc(sizeof(*chip), GFP_KERNEL); 871da177e4SLinus Torvalds if (chip == NULL) 881da177e4SLinus Torvalds return -ENOMEM; 891da177e4SLinus Torvalds spin_lock_init(&chip->lock); 901da177e4SLinus Torvalds chip->card = card; 911da177e4SLinus Torvalds chip->read = read; 921da177e4SLinus Torvalds chip->write = write; 931da177e4SLinus Torvalds chip->private_data = private_data; 941da177e4SLinus Torvalds init_timer(&chip->timer); 951da177e4SLinus Torvalds chip->timer.data = (unsigned long)chip; 961da177e4SLinus Torvalds chip->timer.function = snd_ak4117_timer; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds for (reg = 0; reg < 5; reg++) 991da177e4SLinus Torvalds chip->regmap[reg] = pgm[reg]; 1001da177e4SLinus Torvalds snd_ak4117_reinit(chip); 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds chip->rcs0 = reg_read(chip, AK4117_REG_RCS0) & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); 1031da177e4SLinus Torvalds chip->rcs1 = reg_read(chip, AK4117_REG_RCS1); 1041da177e4SLinus Torvalds chip->rcs2 = reg_read(chip, AK4117_REG_RCS2); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds if ((err = snd_device_new(card, SNDRV_DEV_CODEC, chip, &ops)) < 0) 1071da177e4SLinus Torvalds goto __fail; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds if (r_ak4117) 1101da177e4SLinus Torvalds *r_ak4117 = chip; 1111da177e4SLinus Torvalds return 0; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds __fail: 1141da177e4SLinus Torvalds snd_ak4117_free(chip); 1151da177e4SLinus Torvalds return err < 0 ? err : -EIO; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 11897f02e05STakashi Iwai void snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds if (reg >= 5) 1211da177e4SLinus Torvalds return; 1221da177e4SLinus Torvalds reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 12597f02e05STakashi Iwai void snd_ak4117_reinit(struct ak4117 *chip) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds del_timer(&chip->timer); 1301da177e4SLinus Torvalds chip->init = 1; 1311da177e4SLinus Torvalds /* bring the chip to reset state and powerdown state */ 1321da177e4SLinus Torvalds reg_write(chip, AK4117_REG_PWRDN, 0); 1331da177e4SLinus Torvalds udelay(200); 1341da177e4SLinus Torvalds /* release reset, but leave powerdown */ 1351da177e4SLinus Torvalds reg_write(chip, AK4117_REG_PWRDN, (old | AK4117_RST) & ~AK4117_PWN); 1361da177e4SLinus Torvalds udelay(200); 1371da177e4SLinus Torvalds for (reg = 1; reg < 5; reg++) 1381da177e4SLinus Torvalds reg_write(chip, reg, chip->regmap[reg]); 1391da177e4SLinus Torvalds /* release powerdown, everything is initialized now */ 1401da177e4SLinus Torvalds reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN); 1411da177e4SLinus Torvalds chip->init = 0; 1421da177e4SLinus Torvalds chip->timer.expires = 1 + jiffies; 1431da177e4SLinus Torvalds add_timer(&chip->timer); 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds static unsigned int external_rate(unsigned char rcs1) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds switch (rcs1 & (AK4117_FS0|AK4117_FS1|AK4117_FS2|AK4117_FS3)) { 1491da177e4SLinus Torvalds case AK4117_FS_32000HZ: return 32000; 1501da177e4SLinus Torvalds case AK4117_FS_44100HZ: return 44100; 1511da177e4SLinus Torvalds case AK4117_FS_48000HZ: return 48000; 1521da177e4SLinus Torvalds case AK4117_FS_88200HZ: return 88200; 1531da177e4SLinus Torvalds case AK4117_FS_96000HZ: return 96000; 1541da177e4SLinus Torvalds case AK4117_FS_176400HZ: return 176400; 1551da177e4SLinus Torvalds case AK4117_FS_192000HZ: return 192000; 1561da177e4SLinus Torvalds default: return 0; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 16097f02e05STakashi Iwai static int snd_ak4117_in_error_info(struct snd_kcontrol *kcontrol, 16197f02e05STakashi Iwai struct snd_ctl_elem_info *uinfo) 1621da177e4SLinus Torvalds { 1631da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1641da177e4SLinus Torvalds uinfo->count = 1; 1651da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1661da177e4SLinus Torvalds uinfo->value.integer.max = LONG_MAX; 1671da177e4SLinus Torvalds return 0; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 17097f02e05STakashi Iwai static int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol, 17197f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1721da177e4SLinus Torvalds { 17397f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 1741da177e4SLinus Torvalds long *ptr; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds spin_lock_irq(&chip->lock); 1771da177e4SLinus Torvalds ptr = (long *)(((char *)chip) + kcontrol->private_value); 1781da177e4SLinus Torvalds ucontrol->value.integer.value[0] = *ptr; 1791da177e4SLinus Torvalds *ptr = 0; 1801da177e4SLinus Torvalds spin_unlock_irq(&chip->lock); 1811da177e4SLinus Torvalds return 0; 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 18497f02e05STakashi Iwai static int snd_ak4117_in_bit_info(struct snd_kcontrol *kcontrol, 18597f02e05STakashi Iwai struct snd_ctl_elem_info *uinfo) 1861da177e4SLinus Torvalds { 1871da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 1881da177e4SLinus Torvalds uinfo->count = 1; 1891da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1901da177e4SLinus Torvalds uinfo->value.integer.max = 1; 1911da177e4SLinus Torvalds return 0; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 19497f02e05STakashi Iwai static int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol, 19597f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1961da177e4SLinus Torvalds { 19797f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 1981da177e4SLinus Torvalds unsigned char reg = kcontrol->private_value & 0xff; 1991da177e4SLinus Torvalds unsigned char bit = (kcontrol->private_value >> 8) & 0xff; 2001da177e4SLinus Torvalds unsigned char inv = (kcontrol->private_value >> 31) & 1; 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; 2031da177e4SLinus Torvalds return 0; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 20697f02e05STakashi Iwai static int snd_ak4117_rx_info(struct snd_kcontrol *kcontrol, 20797f02e05STakashi Iwai struct snd_ctl_elem_info *uinfo) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2101da177e4SLinus Torvalds uinfo->count = 1; 2111da177e4SLinus Torvalds uinfo->value.integer.min = 0; 2121da177e4SLinus Torvalds uinfo->value.integer.max = 1; 2131da177e4SLinus Torvalds return 0; 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 21697f02e05STakashi Iwai static int snd_ak4117_rx_get(struct snd_kcontrol *kcontrol, 21797f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2181da177e4SLinus Torvalds { 21997f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0; 2221da177e4SLinus Torvalds return 0; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 22597f02e05STakashi Iwai static int snd_ak4117_rx_put(struct snd_kcontrol *kcontrol, 22697f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2271da177e4SLinus Torvalds { 22897f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2291da177e4SLinus Torvalds int change; 2301da177e4SLinus Torvalds u8 old_val; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds spin_lock_irq(&chip->lock); 2331da177e4SLinus Torvalds old_val = chip->regmap[AK4117_REG_IO]; 2341da177e4SLinus Torvalds change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0); 2351da177e4SLinus Torvalds if (change) 2361da177e4SLinus Torvalds reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0)); 2371da177e4SLinus Torvalds spin_unlock_irq(&chip->lock); 2381da177e4SLinus Torvalds return change; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 24197f02e05STakashi Iwai static int snd_ak4117_rate_info(struct snd_kcontrol *kcontrol, 24297f02e05STakashi Iwai struct snd_ctl_elem_info *uinfo) 2431da177e4SLinus Torvalds { 2441da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2451da177e4SLinus Torvalds uinfo->count = 1; 2461da177e4SLinus Torvalds uinfo->value.integer.min = 0; 2471da177e4SLinus Torvalds uinfo->value.integer.max = 192000; 2481da177e4SLinus Torvalds return 0; 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds 25197f02e05STakashi Iwai static int snd_ak4117_rate_get(struct snd_kcontrol *kcontrol, 25297f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2531da177e4SLinus Torvalds { 25497f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1)); 2571da177e4SLinus Torvalds return 0; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 26097f02e05STakashi Iwai static int snd_ak4117_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2611da177e4SLinus Torvalds { 2621da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 2631da177e4SLinus Torvalds uinfo->count = 1; 2641da177e4SLinus Torvalds return 0; 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 26797f02e05STakashi Iwai static int snd_ak4117_spdif_get(struct snd_kcontrol *kcontrol, 26897f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2691da177e4SLinus Torvalds { 27097f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 2711da177e4SLinus Torvalds unsigned i; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++) 2741da177e4SLinus Torvalds ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i); 2751da177e4SLinus Torvalds return 0; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 27897f02e05STakashi Iwai static int snd_ak4117_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 2811da177e4SLinus Torvalds uinfo->count = 1; 2821da177e4SLinus Torvalds return 0; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds 28597f02e05STakashi Iwai static int snd_ak4117_spdif_mask_get(struct snd_kcontrol *kcontrol, 28697f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2871da177e4SLinus Torvalds { 2881da177e4SLinus Torvalds memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE); 2891da177e4SLinus Torvalds return 0; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds 29297f02e05STakashi Iwai static int snd_ak4117_spdif_pinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2951da177e4SLinus Torvalds uinfo->value.integer.min = 0; 2961da177e4SLinus Torvalds uinfo->value.integer.max = 0xffff; 2971da177e4SLinus Torvalds uinfo->count = 4; 2981da177e4SLinus Torvalds return 0; 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 30197f02e05STakashi Iwai static int snd_ak4117_spdif_pget(struct snd_kcontrol *kcontrol, 30297f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3031da177e4SLinus Torvalds { 30497f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 3051da177e4SLinus Torvalds unsigned short tmp; 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds ucontrol->value.integer.value[0] = 0xf8f2; 3081da177e4SLinus Torvalds ucontrol->value.integer.value[1] = 0x4e1f; 3091da177e4SLinus Torvalds tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8); 3101da177e4SLinus Torvalds ucontrol->value.integer.value[2] = tmp; 3111da177e4SLinus Torvalds tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8); 3121da177e4SLinus Torvalds ucontrol->value.integer.value[3] = tmp; 3131da177e4SLinus Torvalds return 0; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 31697f02e05STakashi Iwai static int snd_ak4117_spdif_qinfo(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 3171da177e4SLinus Torvalds { 3181da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 3191da177e4SLinus Torvalds uinfo->count = AK4117_REG_QSUB_SIZE; 3201da177e4SLinus Torvalds return 0; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds 32397f02e05STakashi Iwai static int snd_ak4117_spdif_qget(struct snd_kcontrol *kcontrol, 32497f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3251da177e4SLinus Torvalds { 32697f02e05STakashi Iwai struct ak4117 *chip = snd_kcontrol_chip(kcontrol); 3271da177e4SLinus Torvalds unsigned i; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds for (i = 0; i < AK4117_REG_QSUB_SIZE; i++) 3301da177e4SLinus Torvalds ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i); 3311da177e4SLinus Torvalds return 0; 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds /* Don't forget to change AK4117_CONTROLS define!!! */ 33597f02e05STakashi Iwai static struct snd_kcontrol_new snd_ak4117_iec958_controls[] = { 3361da177e4SLinus Torvalds { 3371da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3381da177e4SLinus Torvalds .name = "IEC958 Parity Errors", 3391da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3401da177e4SLinus Torvalds .info = snd_ak4117_in_error_info, 3411da177e4SLinus Torvalds .get = snd_ak4117_in_error_get, 34297f02e05STakashi Iwai .private_value = offsetof(struct ak4117, parity_errors), 3431da177e4SLinus Torvalds }, 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3461da177e4SLinus Torvalds .name = "IEC958 V-Bit Errors", 3471da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3481da177e4SLinus Torvalds .info = snd_ak4117_in_error_info, 3491da177e4SLinus Torvalds .get = snd_ak4117_in_error_get, 35097f02e05STakashi Iwai .private_value = offsetof(struct ak4117, v_bit_errors), 3511da177e4SLinus Torvalds }, 3521da177e4SLinus Torvalds { 3531da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3541da177e4SLinus Torvalds .name = "IEC958 C-CRC Errors", 3551da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3561da177e4SLinus Torvalds .info = snd_ak4117_in_error_info, 3571da177e4SLinus Torvalds .get = snd_ak4117_in_error_get, 35897f02e05STakashi Iwai .private_value = offsetof(struct ak4117, ccrc_errors), 3591da177e4SLinus Torvalds }, 3601da177e4SLinus Torvalds { 3611da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3621da177e4SLinus Torvalds .name = "IEC958 Q-CRC Errors", 3631da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3641da177e4SLinus Torvalds .info = snd_ak4117_in_error_info, 3651da177e4SLinus Torvalds .get = snd_ak4117_in_error_get, 36697f02e05STakashi Iwai .private_value = offsetof(struct ak4117, qcrc_errors), 3671da177e4SLinus Torvalds }, 3681da177e4SLinus Torvalds { 3691da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3701da177e4SLinus Torvalds .name = "IEC958 External Rate", 3711da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3721da177e4SLinus Torvalds .info = snd_ak4117_rate_info, 3731da177e4SLinus Torvalds .get = snd_ak4117_rate_get, 3741da177e4SLinus Torvalds }, 3751da177e4SLinus Torvalds { 3761da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3771da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), 3781da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 3791da177e4SLinus Torvalds .info = snd_ak4117_spdif_mask_info, 3801da177e4SLinus Torvalds .get = snd_ak4117_spdif_mask_get, 3811da177e4SLinus Torvalds }, 3821da177e4SLinus Torvalds { 3831da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3841da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), 3851da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3861da177e4SLinus Torvalds .info = snd_ak4117_spdif_info, 3871da177e4SLinus Torvalds .get = snd_ak4117_spdif_get, 3881da177e4SLinus Torvalds }, 3891da177e4SLinus Torvalds { 3901da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3911da177e4SLinus Torvalds .name = "IEC958 Preample Capture Default", 3921da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 3931da177e4SLinus Torvalds .info = snd_ak4117_spdif_pinfo, 3941da177e4SLinus Torvalds .get = snd_ak4117_spdif_pget, 3951da177e4SLinus Torvalds }, 3961da177e4SLinus Torvalds { 3971da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 3981da177e4SLinus Torvalds .name = "IEC958 Q-subcode Capture Default", 3991da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4001da177e4SLinus Torvalds .info = snd_ak4117_spdif_qinfo, 4011da177e4SLinus Torvalds .get = snd_ak4117_spdif_qget, 4021da177e4SLinus Torvalds }, 4031da177e4SLinus Torvalds { 4041da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4051da177e4SLinus Torvalds .name = "IEC958 Audio", 4061da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4071da177e4SLinus Torvalds .info = snd_ak4117_in_bit_info, 4081da177e4SLinus Torvalds .get = snd_ak4117_in_bit_get, 4091da177e4SLinus Torvalds .private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0, 4101da177e4SLinus Torvalds }, 4111da177e4SLinus Torvalds { 4121da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4131da177e4SLinus Torvalds .name = "IEC958 Non-PCM Bitstream", 4141da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4151da177e4SLinus Torvalds .info = snd_ak4117_in_bit_info, 4161da177e4SLinus Torvalds .get = snd_ak4117_in_bit_get, 4171da177e4SLinus Torvalds .private_value = (5<<8) | AK4117_REG_RCS1, 4181da177e4SLinus Torvalds }, 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4211da177e4SLinus Torvalds .name = "IEC958 DTS Bitstream", 4221da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 4231da177e4SLinus Torvalds .info = snd_ak4117_in_bit_info, 4241da177e4SLinus Torvalds .get = snd_ak4117_in_bit_get, 4251da177e4SLinus Torvalds .private_value = (6<<8) | AK4117_REG_RCS1, 4261da177e4SLinus Torvalds }, 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 4291da177e4SLinus Torvalds .name = "AK4117 Input Select", 4301da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE, 4311da177e4SLinus Torvalds .info = snd_ak4117_rx_info, 4321da177e4SLinus Torvalds .get = snd_ak4117_rx_get, 4331da177e4SLinus Torvalds .put = snd_ak4117_rx_put, 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds }; 4361da177e4SLinus Torvalds 43797f02e05STakashi Iwai int snd_ak4117_build(struct ak4117 *ak4117, struct snd_pcm_substream *cap_substream) 4381da177e4SLinus Torvalds { 43997f02e05STakashi Iwai struct snd_kcontrol *kctl; 4401da177e4SLinus Torvalds unsigned int idx; 4411da177e4SLinus Torvalds int err; 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds snd_assert(cap_substream, return -EINVAL); 4441da177e4SLinus Torvalds ak4117->substream = cap_substream; 4451da177e4SLinus Torvalds for (idx = 0; idx < AK4117_CONTROLS; idx++) { 4461da177e4SLinus Torvalds kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117); 4471da177e4SLinus Torvalds if (kctl == NULL) 4481da177e4SLinus Torvalds return -ENOMEM; 4491da177e4SLinus Torvalds kctl->id.device = cap_substream->pcm->device; 4501da177e4SLinus Torvalds kctl->id.subdevice = cap_substream->number; 4511da177e4SLinus Torvalds err = snd_ctl_add(ak4117->card, kctl); 4521da177e4SLinus Torvalds if (err < 0) 4531da177e4SLinus Torvalds return err; 4541da177e4SLinus Torvalds ak4117->kctls[idx] = kctl; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds return 0; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds 45997f02e05STakashi Iwai int snd_ak4117_external_rate(struct ak4117 *ak4117) 4601da177e4SLinus Torvalds { 4611da177e4SLinus Torvalds unsigned char rcs1; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds rcs1 = reg_read(ak4117, AK4117_REG_RCS1); 4641da177e4SLinus Torvalds return external_rate(rcs1); 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 46797f02e05STakashi Iwai int snd_ak4117_check_rate_and_errors(struct ak4117 *ak4117, unsigned int flags) 4681da177e4SLinus Torvalds { 46997f02e05STakashi Iwai struct snd_pcm_runtime *runtime = ak4117->substream ? ak4117->substream->runtime : NULL; 4701da177e4SLinus Torvalds unsigned long _flags; 4711da177e4SLinus Torvalds int res = 0; 4721da177e4SLinus Torvalds unsigned char rcs0, rcs1, rcs2; 4731da177e4SLinus Torvalds unsigned char c0, c1; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds rcs1 = reg_read(ak4117, AK4117_REG_RCS1); 4761da177e4SLinus Torvalds if (flags & AK4117_CHECK_NO_STAT) 4771da177e4SLinus Torvalds goto __rate; 4781da177e4SLinus Torvalds rcs0 = reg_read(ak4117, AK4117_REG_RCS0); 4791da177e4SLinus Torvalds rcs2 = reg_read(ak4117, AK4117_REG_RCS2); 48099b359baSTakashi Iwai // printk(KERN_DEBUG "AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2); 4811da177e4SLinus Torvalds spin_lock_irqsave(&ak4117->lock, _flags); 4821da177e4SLinus Torvalds if (rcs0 & AK4117_PAR) 4831da177e4SLinus Torvalds ak4117->parity_errors++; 4841da177e4SLinus Torvalds if (rcs0 & AK4117_V) 4851da177e4SLinus Torvalds ak4117->v_bit_errors++; 4861da177e4SLinus Torvalds if (rcs2 & AK4117_CCRC) 4871da177e4SLinus Torvalds ak4117->ccrc_errors++; 4881da177e4SLinus Torvalds if (rcs2 & AK4117_QCRC) 4891da177e4SLinus Torvalds ak4117->qcrc_errors++; 4901da177e4SLinus Torvalds c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^ 4911da177e4SLinus Torvalds (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)); 4921da177e4SLinus Torvalds c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^ 4931da177e4SLinus Torvalds (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)); 4941da177e4SLinus Torvalds ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); 4951da177e4SLinus Torvalds ak4117->rcs1 = rcs1; 4961da177e4SLinus Torvalds ak4117->rcs2 = rcs2; 4971da177e4SLinus Torvalds spin_unlock_irqrestore(&ak4117->lock, _flags); 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds if (rcs0 & AK4117_PAR) 5001da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id); 5011da177e4SLinus Torvalds if (rcs0 & AK4117_V) 5021da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id); 5031da177e4SLinus Torvalds if (rcs2 & AK4117_CCRC) 5041da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id); 5051da177e4SLinus Torvalds if (rcs2 & AK4117_QCRC) 5061da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id); 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds /* rate change */ 5091da177e4SLinus Torvalds if (c1 & 0x0f) 5101da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id); 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT)) 5131da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id); 5141da177e4SLinus Torvalds if (c0 & AK4117_QINT) 5151da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds if (c0 & AK4117_AUDION) 5181da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id); 5191da177e4SLinus Torvalds if (c1 & AK4117_NPCM) 5201da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id); 5211da177e4SLinus Torvalds if (c1 & AK4117_DTSCD) 5221da177e4SLinus Torvalds snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id); 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds if (ak4117->change_callback && (c0 | c1) != 0) 5251da177e4SLinus Torvalds ak4117->change_callback(ak4117, c0, c1); 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds __rate: 5281da177e4SLinus Torvalds /* compare rate */ 5291da177e4SLinus Torvalds res = external_rate(rcs1); 5301da177e4SLinus Torvalds if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) { 5311da177e4SLinus Torvalds snd_pcm_stream_lock_irqsave(ak4117->substream, _flags); 5321da177e4SLinus Torvalds if (snd_pcm_running(ak4117->substream)) { 53399b359baSTakashi Iwai // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res); 5341da177e4SLinus Torvalds snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING); 5351da177e4SLinus Torvalds wake_up(&runtime->sleep); 5361da177e4SLinus Torvalds res = 1; 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags); 5391da177e4SLinus Torvalds } 5401da177e4SLinus Torvalds return res; 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds static void snd_ak4117_timer(unsigned long data) 5441da177e4SLinus Torvalds { 54597f02e05STakashi Iwai struct ak4117 *chip = (struct ak4117 *)data; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds if (chip->init) 5481da177e4SLinus Torvalds return; 5491da177e4SLinus Torvalds snd_ak4117_check_rate_and_errors(chip, 0); 5501da177e4SLinus Torvalds chip->timer.expires = 1 + jiffies; 5511da177e4SLinus Torvalds add_timer(&chip->timer); 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ak4117_create); 5551da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ak4117_reg_write); 5561da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ak4117_reinit); 5571da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ak4117_build); 5581da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ak4117_external_rate); 5591da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ak4117_check_rate_and_errors); 560