xref: /openbmc/linux/sound/pci/ice1712/ak4xxx.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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