1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * ALSA driver for ICEnsemble ICE1712 (Envy24) 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 9*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 10*1da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 11*1da177e4SLinus Torvalds * (at your option) any later version. 12*1da177e4SLinus Torvalds * 13*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 14*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*1da177e4SLinus Torvalds * GNU General Public License for more details. 17*1da177e4SLinus Torvalds * 18*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 19*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 20*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*1da177e4SLinus Torvalds * 22*1da177e4SLinus Torvalds */ 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds #include <sound/driver.h> 25*1da177e4SLinus Torvalds #include <asm/io.h> 26*1da177e4SLinus Torvalds #include <linux/delay.h> 27*1da177e4SLinus Torvalds #include <linux/interrupt.h> 28*1da177e4SLinus Torvalds #include <linux/init.h> 29*1da177e4SLinus Torvalds #include <sound/core.h> 30*1da177e4SLinus Torvalds #include <sound/initval.h> 31*1da177e4SLinus Torvalds #include "ice1712.h" 32*1da177e4SLinus Torvalds 33*1da177e4SLinus Torvalds MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 34*1da177e4SLinus Torvalds MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface"); 35*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds static void snd_ice1712_akm4xxx_lock(akm4xxx_t *ak, int chip) 38*1da177e4SLinus Torvalds { 39*1da177e4SLinus Torvalds ice1712_t *ice = ak->private_data[0]; 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds snd_ice1712_save_gpio_status(ice); 42*1da177e4SLinus Torvalds } 43*1da177e4SLinus Torvalds 44*1da177e4SLinus Torvalds static void snd_ice1712_akm4xxx_unlock(akm4xxx_t *ak, int chip) 45*1da177e4SLinus Torvalds { 46*1da177e4SLinus Torvalds ice1712_t *ice = ak->private_data[0]; 47*1da177e4SLinus Torvalds 48*1da177e4SLinus Torvalds snd_ice1712_restore_gpio_status(ice); 49*1da177e4SLinus Torvalds } 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds /* 52*1da177e4SLinus Torvalds * write AK4xxx register 53*1da177e4SLinus Torvalds */ 54*1da177e4SLinus Torvalds static void snd_ice1712_akm4xxx_write(akm4xxx_t *ak, int chip, 55*1da177e4SLinus Torvalds unsigned char addr, unsigned char data) 56*1da177e4SLinus Torvalds { 57*1da177e4SLinus Torvalds unsigned int tmp; 58*1da177e4SLinus Torvalds int idx; 59*1da177e4SLinus Torvalds unsigned int addrdata; 60*1da177e4SLinus Torvalds struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; 61*1da177e4SLinus Torvalds ice1712_t *ice = ak->private_data[0]; 62*1da177e4SLinus Torvalds 63*1da177e4SLinus Torvalds snd_assert(chip >= 0 && chip < 4, return); 64*1da177e4SLinus Torvalds 65*1da177e4SLinus Torvalds tmp = snd_ice1712_gpio_read(ice); 66*1da177e4SLinus Torvalds tmp |= priv->add_flags; 67*1da177e4SLinus Torvalds tmp &= ~priv->mask_flags; 68*1da177e4SLinus Torvalds if (priv->cs_mask == priv->cs_addr) { 69*1da177e4SLinus Torvalds if (priv->cif) { 70*1da177e4SLinus Torvalds tmp |= priv->cs_mask; /* start without chip select */ 71*1da177e4SLinus Torvalds } else { 72*1da177e4SLinus Torvalds tmp &= ~priv->cs_mask; /* chip select low */ 73*1da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 74*1da177e4SLinus Torvalds udelay(1); 75*1da177e4SLinus Torvalds } 76*1da177e4SLinus Torvalds } else { 77*1da177e4SLinus Torvalds /* doesn't handle cf=1 yet */ 78*1da177e4SLinus Torvalds tmp &= ~priv->cs_mask; 79*1da177e4SLinus Torvalds tmp |= priv->cs_addr; 80*1da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 81*1da177e4SLinus Torvalds udelay(1); 82*1da177e4SLinus Torvalds } 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds /* build I2C address + data byte */ 85*1da177e4SLinus Torvalds addrdata = (priv->caddr << 6) | 0x20 | (addr & 0x1f); 86*1da177e4SLinus Torvalds addrdata = (addrdata << 8) | data; 87*1da177e4SLinus Torvalds for (idx = 15; idx >= 0; idx--) { 88*1da177e4SLinus Torvalds /* drop clock */ 89*1da177e4SLinus Torvalds tmp &= ~priv->clk_mask; 90*1da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 91*1da177e4SLinus Torvalds udelay(1); 92*1da177e4SLinus Torvalds /* set data */ 93*1da177e4SLinus Torvalds if (addrdata & (1 << idx)) 94*1da177e4SLinus Torvalds tmp |= priv->data_mask; 95*1da177e4SLinus Torvalds else 96*1da177e4SLinus Torvalds tmp &= ~priv->data_mask; 97*1da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 98*1da177e4SLinus Torvalds udelay(1); 99*1da177e4SLinus Torvalds /* raise clock */ 100*1da177e4SLinus Torvalds tmp |= priv->clk_mask; 101*1da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 102*1da177e4SLinus Torvalds udelay(1); 103*1da177e4SLinus Torvalds } 104*1da177e4SLinus Torvalds 105*1da177e4SLinus Torvalds if (priv->cs_mask == priv->cs_addr) { 106*1da177e4SLinus Torvalds if (priv->cif) { 107*1da177e4SLinus Torvalds /* assert a cs pulse to trigger */ 108*1da177e4SLinus Torvalds tmp &= ~priv->cs_mask; 109*1da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 110*1da177e4SLinus Torvalds udelay(1); 111*1da177e4SLinus Torvalds } 112*1da177e4SLinus Torvalds tmp |= priv->cs_mask; /* chip select high to trigger */ 113*1da177e4SLinus Torvalds } else { 114*1da177e4SLinus Torvalds tmp &= ~priv->cs_mask; 115*1da177e4SLinus Torvalds tmp |= priv->cs_none; /* deselect address */ 116*1da177e4SLinus Torvalds } 117*1da177e4SLinus Torvalds snd_ice1712_gpio_write(ice, tmp); 118*1da177e4SLinus Torvalds udelay(1); 119*1da177e4SLinus Torvalds } 120*1da177e4SLinus Torvalds 121*1da177e4SLinus Torvalds /* 122*1da177e4SLinus Torvalds * initialize the akm4xxx_t record with the template 123*1da177e4SLinus Torvalds */ 124*1da177e4SLinus Torvalds int snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *temp, 125*1da177e4SLinus Torvalds const struct snd_ak4xxx_private *_priv, ice1712_t *ice) 126*1da177e4SLinus Torvalds { 127*1da177e4SLinus Torvalds struct snd_ak4xxx_private *priv; 128*1da177e4SLinus Torvalds 129*1da177e4SLinus Torvalds if (_priv != NULL) { 130*1da177e4SLinus Torvalds priv = kmalloc(sizeof(*priv), GFP_KERNEL); 131*1da177e4SLinus Torvalds if (priv == NULL) 132*1da177e4SLinus Torvalds return -ENOMEM; 133*1da177e4SLinus Torvalds *priv = *_priv; 134*1da177e4SLinus Torvalds } else { 135*1da177e4SLinus Torvalds priv = NULL; 136*1da177e4SLinus Torvalds } 137*1da177e4SLinus Torvalds *ak = *temp; 138*1da177e4SLinus Torvalds ak->card = ice->card; 139*1da177e4SLinus Torvalds ak->private_value[0] = (unsigned long)priv; 140*1da177e4SLinus Torvalds ak->private_data[0] = ice; 141*1da177e4SLinus Torvalds if (ak->ops.lock == NULL) 142*1da177e4SLinus Torvalds ak->ops.lock = snd_ice1712_akm4xxx_lock; 143*1da177e4SLinus Torvalds if (ak->ops.unlock == NULL) 144*1da177e4SLinus Torvalds ak->ops.unlock = snd_ice1712_akm4xxx_unlock; 145*1da177e4SLinus Torvalds if (ak->ops.write == NULL) 146*1da177e4SLinus Torvalds ak->ops.write = snd_ice1712_akm4xxx_write; 147*1da177e4SLinus Torvalds snd_akm4xxx_init(ak); 148*1da177e4SLinus Torvalds return 0; 149*1da177e4SLinus Torvalds } 150*1da177e4SLinus Torvalds 151*1da177e4SLinus Torvalds void snd_ice1712_akm4xxx_free(ice1712_t *ice) 152*1da177e4SLinus Torvalds { 153*1da177e4SLinus Torvalds unsigned int akidx; 154*1da177e4SLinus Torvalds if (ice->akm == NULL) 155*1da177e4SLinus Torvalds return; 156*1da177e4SLinus Torvalds for (akidx = 0; akidx < ice->akm_codecs; akidx++) { 157*1da177e4SLinus Torvalds akm4xxx_t *ak = &ice->akm[akidx]; 158*1da177e4SLinus Torvalds kfree((void*)ak->private_value[0]); 159*1da177e4SLinus Torvalds } 160*1da177e4SLinus Torvalds kfree(ice->akm); 161*1da177e4SLinus Torvalds } 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds /* 164*1da177e4SLinus Torvalds * build AK4xxx controls 165*1da177e4SLinus Torvalds */ 166*1da177e4SLinus Torvalds int snd_ice1712_akm4xxx_build_controls(ice1712_t *ice) 167*1da177e4SLinus Torvalds { 168*1da177e4SLinus Torvalds unsigned int akidx; 169*1da177e4SLinus Torvalds int err; 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds for (akidx = 0; akidx < ice->akm_codecs; akidx++) { 172*1da177e4SLinus Torvalds akm4xxx_t *ak = &ice->akm[akidx]; 173*1da177e4SLinus Torvalds err = snd_akm4xxx_build_controls(ak); 174*1da177e4SLinus Torvalds if (err < 0) 175*1da177e4SLinus Torvalds return err; 176*1da177e4SLinus Torvalds } 177*1da177e4SLinus Torvalds return 0; 178*1da177e4SLinus Torvalds } 179*1da177e4SLinus Torvalds 180*1da177e4SLinus Torvalds static int __init alsa_ice1712_akm4xxx_module_init(void) 181*1da177e4SLinus Torvalds { 182*1da177e4SLinus Torvalds return 0; 183*1da177e4SLinus Torvalds } 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds static void __exit alsa_ice1712_akm4xxx_module_exit(void) 186*1da177e4SLinus Torvalds { 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds 189*1da177e4SLinus Torvalds module_init(alsa_ice1712_akm4xxx_module_init) 190*1da177e4SLinus Torvalds module_exit(alsa_ice1712_akm4xxx_module_exit) 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ice1712_akm4xxx_init); 193*1da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ice1712_akm4xxx_free); 194*1da177e4SLinus Torvalds EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls); 195