11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * ALSA driver for ICEnsemble ICE1712 (Envy24) 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface 51da177e4SLinus Torvalds * 6c1017a4cSJaroslav Kysela * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4SLinus Torvalds * (at your option) any later version. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 141da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4SLinus Torvalds * GNU General Public License for more details. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include <asm/io.h> 251da177e4SLinus Torvalds #include <linux/delay.h> 261da177e4SLinus Torvalds #include <linux/interrupt.h> 27*5a0e3ad6STejun Heo #include <linux/slab.h> 281da177e4SLinus Torvalds #include <linux/init.h> 291da177e4SLinus Torvalds #include <sound/core.h> 301da177e4SLinus Torvalds #include <sound/initval.h> 311da177e4SLinus Torvalds #include "ice1712.h" 321da177e4SLinus Torvalds 33c1017a4cSJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 341da177e4SLinus Torvalds MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface"); 351da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 361da177e4SLinus Torvalds 376ca308d4STakashi Iwai static void snd_ice1712_akm4xxx_lock(struct snd_akm4xxx *ak, int chip) 381da177e4SLinus Torvalds { 396ca308d4STakashi Iwai struct snd_ice1712 *ice = ak->private_data[0]; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds snd_ice1712_save_gpio_status(ice); 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 446ca308d4STakashi Iwai static void snd_ice1712_akm4xxx_unlock(struct snd_akm4xxx *ak, int chip) 451da177e4SLinus Torvalds { 466ca308d4STakashi Iwai struct snd_ice1712 *ice = ak->private_data[0]; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds snd_ice1712_restore_gpio_status(ice); 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /* 521da177e4SLinus Torvalds * write AK4xxx register 531da177e4SLinus Torvalds */ 546ca308d4STakashi Iwai static void snd_ice1712_akm4xxx_write(struct snd_akm4xxx *ak, int chip, 551da177e4SLinus Torvalds unsigned char addr, unsigned char data) 561da177e4SLinus Torvalds { 571da177e4SLinus Torvalds unsigned int tmp; 581da177e4SLinus Torvalds int idx; 591da177e4SLinus Torvalds unsigned int addrdata; 601da177e4SLinus Torvalds struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; 616ca308d4STakashi Iwai struct snd_ice1712 *ice = ak->private_data[0]; 621da177e4SLinus Torvalds 63da3cec35STakashi Iwai if (snd_BUG_ON(chip < 0 || chip >= 4)) 64da3cec35STakashi Iwai return; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds tmp = snd_ice1712_gpio_read(ice); 671da177e4SLinus Torvalds tmp |= priv->add_flags; 681da177e4SLinus Torvalds tmp &= ~priv->mask_flags; 691da177e4SLinus Torvalds if (priv->cs_mask == priv->cs_addr) { 701da177e4SLinus Torvalds if (priv->cif) { 711da177e4SLinus Torvalds tmp |= priv->cs_mask; /* start without chip select */ 721da177e4SLinus Torvalds } else { 731da177e4SLinus Torvalds tmp &= ~priv->cs_mask; /* chip select low */ 741da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 751da177e4SLinus Torvalds udelay(1); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds } else { 781da177e4SLinus Torvalds /* doesn't handle cf=1 yet */ 791da177e4SLinus Torvalds tmp &= ~priv->cs_mask; 801da177e4SLinus Torvalds tmp |= priv->cs_addr; 811da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 821da177e4SLinus Torvalds udelay(1); 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* build I2C address + data byte */ 861da177e4SLinus Torvalds addrdata = (priv->caddr << 6) | 0x20 | (addr & 0x1f); 871da177e4SLinus Torvalds addrdata = (addrdata << 8) | data; 881da177e4SLinus Torvalds for (idx = 15; idx >= 0; idx--) { 891da177e4SLinus Torvalds /* drop clock */ 901da177e4SLinus Torvalds tmp &= ~priv->clk_mask; 911da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 921da177e4SLinus Torvalds udelay(1); 931da177e4SLinus Torvalds /* set data */ 941da177e4SLinus Torvalds if (addrdata & (1 << idx)) 951da177e4SLinus Torvalds tmp |= priv->data_mask; 961da177e4SLinus Torvalds else 971da177e4SLinus Torvalds tmp &= ~priv->data_mask; 981da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 991da177e4SLinus Torvalds udelay(1); 1001da177e4SLinus Torvalds /* raise clock */ 1011da177e4SLinus Torvalds tmp |= priv->clk_mask; 1021da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 1031da177e4SLinus Torvalds udelay(1); 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds if (priv->cs_mask == priv->cs_addr) { 1071da177e4SLinus Torvalds if (priv->cif) { 1081da177e4SLinus Torvalds /* assert a cs pulse to trigger */ 1091da177e4SLinus Torvalds tmp &= ~priv->cs_mask; 1101da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 1111da177e4SLinus Torvalds udelay(1); 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds tmp |= priv->cs_mask; /* chip select high to trigger */ 1141da177e4SLinus Torvalds } else { 1151da177e4SLinus Torvalds tmp &= ~priv->cs_mask; 1161da177e4SLinus Torvalds tmp |= priv->cs_none; /* deselect address */ 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 1191da177e4SLinus Torvalds udelay(1); 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* 1236ca308d4STakashi Iwai * initialize the struct snd_akm4xxx record with the template 1241da177e4SLinus Torvalds */ 1256ca308d4STakashi Iwai int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *temp, 1266ca308d4STakashi Iwai const struct snd_ak4xxx_private *_priv, struct snd_ice1712 *ice) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds struct snd_ak4xxx_private *priv; 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds if (_priv != NULL) { 1311da177e4SLinus Torvalds priv = kmalloc(sizeof(*priv), GFP_KERNEL); 1321da177e4SLinus Torvalds if (priv == NULL) 1331da177e4SLinus Torvalds return -ENOMEM; 1341da177e4SLinus Torvalds *priv = *_priv; 1351da177e4SLinus Torvalds } else { 1361da177e4SLinus Torvalds priv = NULL; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds *ak = *temp; 1391da177e4SLinus Torvalds ak->card = ice->card; 1401da177e4SLinus Torvalds ak->private_value[0] = (unsigned long)priv; 1411da177e4SLinus Torvalds ak->private_data[0] = ice; 1421da177e4SLinus Torvalds if (ak->ops.lock == NULL) 1431da177e4SLinus Torvalds ak->ops.lock = snd_ice1712_akm4xxx_lock; 1441da177e4SLinus Torvalds if (ak->ops.unlock == NULL) 1451da177e4SLinus Torvalds ak->ops.unlock = snd_ice1712_akm4xxx_unlock; 1461da177e4SLinus Torvalds if (ak->ops.write == NULL) 1471da177e4SLinus Torvalds ak->ops.write = snd_ice1712_akm4xxx_write; 1481da177e4SLinus Torvalds snd_akm4xxx_init(ak); 1491da177e4SLinus Torvalds return 0; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1526ca308d4STakashi Iwai void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds unsigned int akidx; 1551da177e4SLinus Torvalds if (ice->akm == NULL) 1561da177e4SLinus Torvalds return; 1571da177e4SLinus Torvalds for (akidx = 0; akidx < ice->akm_codecs; akidx++) { 1586ca308d4STakashi Iwai struct snd_akm4xxx *ak = &ice->akm[akidx]; 1591da177e4SLinus Torvalds kfree((void*)ak->private_value[0]); 1601da177e4SLinus Torvalds } 1611da177e4SLinus Torvalds kfree(ice->akm); 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds /* 1651da177e4SLinus Torvalds * build AK4xxx controls 1661da177e4SLinus Torvalds */ 1676ca308d4STakashi Iwai int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice) 1681da177e4SLinus Torvalds { 1691da177e4SLinus Torvalds unsigned int akidx; 1701da177e4SLinus Torvalds int err; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds for (akidx = 0; akidx < ice->akm_codecs; akidx++) { 1736ca308d4STakashi Iwai struct snd_akm4xxx *ak = &ice->akm[akidx]; 1741da177e4SLinus Torvalds err = snd_akm4xxx_build_controls(ak); 1751da177e4SLinus Torvalds if (err < 0) 1761da177e4SLinus Torvalds return err; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds return 0; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds static int __init alsa_ice1712_akm4xxx_module_init(void) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds return 0; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds static void __exit alsa_ice1712_akm4xxx_module_exit(void) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds module_init(alsa_ice1712_akm4xxx_module_init) 1911da177e4SLinus Torvalds module_exit(alsa_ice1712_akm4xxx_module_exit) 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ice1712_akm4xxx_init); 1941da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ice1712_akm4xxx_free); 1951da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls); 196