xref: /OK3568_Linux_fs/kernel/sound/pci/ice1712/ak4xxx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *   ALSA driver for ICEnsemble ICE1712 (Envy24)
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *   AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *	Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/io.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <sound/core.h>
17*4882a593Smuzhiyun #include <sound/initval.h>
18*4882a593Smuzhiyun #include "ice1712.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
21*4882a593Smuzhiyun MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface");
22*4882a593Smuzhiyun MODULE_LICENSE("GPL");
23*4882a593Smuzhiyun 
snd_ice1712_akm4xxx_lock(struct snd_akm4xxx * ak,int chip)24*4882a593Smuzhiyun static void snd_ice1712_akm4xxx_lock(struct snd_akm4xxx *ak, int chip)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct snd_ice1712 *ice = ak->private_data[0];
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	snd_ice1712_save_gpio_status(ice);
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
snd_ice1712_akm4xxx_unlock(struct snd_akm4xxx * ak,int chip)31*4882a593Smuzhiyun static void snd_ice1712_akm4xxx_unlock(struct snd_akm4xxx *ak, int chip)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	struct snd_ice1712 *ice = ak->private_data[0];
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	snd_ice1712_restore_gpio_status(ice);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /*
39*4882a593Smuzhiyun  * write AK4xxx register
40*4882a593Smuzhiyun  */
snd_ice1712_akm4xxx_write(struct snd_akm4xxx * ak,int chip,unsigned char addr,unsigned char data)41*4882a593Smuzhiyun static void snd_ice1712_akm4xxx_write(struct snd_akm4xxx *ak, int chip,
42*4882a593Smuzhiyun 				      unsigned char addr, unsigned char data)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	unsigned int tmp;
45*4882a593Smuzhiyun 	int idx;
46*4882a593Smuzhiyun 	unsigned int addrdata;
47*4882a593Smuzhiyun 	struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
48*4882a593Smuzhiyun 	struct snd_ice1712 *ice = ak->private_data[0];
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	if (snd_BUG_ON(chip < 0 || chip >= 4))
51*4882a593Smuzhiyun 		return;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	tmp = snd_ice1712_gpio_read(ice);
54*4882a593Smuzhiyun 	tmp |= priv->add_flags;
55*4882a593Smuzhiyun 	tmp &= ~priv->mask_flags;
56*4882a593Smuzhiyun 	if (priv->cs_mask == priv->cs_addr) {
57*4882a593Smuzhiyun 		if (priv->cif) {
58*4882a593Smuzhiyun 			tmp |= priv->cs_mask; /* start without chip select */
59*4882a593Smuzhiyun 		}  else {
60*4882a593Smuzhiyun 			tmp &= ~priv->cs_mask; /* chip select low */
61*4882a593Smuzhiyun 			snd_ice1712_gpio_write(ice, tmp);
62*4882a593Smuzhiyun 			udelay(1);
63*4882a593Smuzhiyun 		}
64*4882a593Smuzhiyun 	} else {
65*4882a593Smuzhiyun 		/* doesn't handle cf=1 yet */
66*4882a593Smuzhiyun 		tmp &= ~priv->cs_mask;
67*4882a593Smuzhiyun 		tmp |= priv->cs_addr;
68*4882a593Smuzhiyun 		snd_ice1712_gpio_write(ice, tmp);
69*4882a593Smuzhiyun 		udelay(1);
70*4882a593Smuzhiyun 	}
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	/* build I2C address + data byte */
73*4882a593Smuzhiyun 	addrdata = (priv->caddr << 6) | 0x20 | (addr & 0x1f);
74*4882a593Smuzhiyun 	addrdata = (addrdata << 8) | data;
75*4882a593Smuzhiyun 	for (idx = 15; idx >= 0; idx--) {
76*4882a593Smuzhiyun 		/* drop clock */
77*4882a593Smuzhiyun 		tmp &= ~priv->clk_mask;
78*4882a593Smuzhiyun 		snd_ice1712_gpio_write(ice, tmp);
79*4882a593Smuzhiyun 		udelay(1);
80*4882a593Smuzhiyun 		/* set data */
81*4882a593Smuzhiyun 		if (addrdata & (1 << idx))
82*4882a593Smuzhiyun 			tmp |= priv->data_mask;
83*4882a593Smuzhiyun 		else
84*4882a593Smuzhiyun 			tmp &= ~priv->data_mask;
85*4882a593Smuzhiyun 		snd_ice1712_gpio_write(ice, tmp);
86*4882a593Smuzhiyun 		udelay(1);
87*4882a593Smuzhiyun 		/* raise clock */
88*4882a593Smuzhiyun 		tmp |= priv->clk_mask;
89*4882a593Smuzhiyun 		snd_ice1712_gpio_write(ice, tmp);
90*4882a593Smuzhiyun 		udelay(1);
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (priv->cs_mask == priv->cs_addr) {
94*4882a593Smuzhiyun 		if (priv->cif) {
95*4882a593Smuzhiyun 			/* assert a cs pulse to trigger */
96*4882a593Smuzhiyun 			tmp &= ~priv->cs_mask;
97*4882a593Smuzhiyun 			snd_ice1712_gpio_write(ice, tmp);
98*4882a593Smuzhiyun 			udelay(1);
99*4882a593Smuzhiyun 		}
100*4882a593Smuzhiyun 		tmp |= priv->cs_mask; /* chip select high to trigger */
101*4882a593Smuzhiyun 	} else {
102*4882a593Smuzhiyun 		tmp &= ~priv->cs_mask;
103*4882a593Smuzhiyun 		tmp |= priv->cs_none; /* deselect address */
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 	snd_ice1712_gpio_write(ice, tmp);
106*4882a593Smuzhiyun 	udelay(1);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /*
110*4882a593Smuzhiyun  * initialize the struct snd_akm4xxx record with the template
111*4882a593Smuzhiyun  */
snd_ice1712_akm4xxx_init(struct snd_akm4xxx * ak,const struct snd_akm4xxx * temp,const struct snd_ak4xxx_private * _priv,struct snd_ice1712 * ice)112*4882a593Smuzhiyun int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *temp,
113*4882a593Smuzhiyun 			     const struct snd_ak4xxx_private *_priv, struct snd_ice1712 *ice)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct snd_ak4xxx_private *priv;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (_priv != NULL) {
118*4882a593Smuzhiyun 		priv = kmalloc(sizeof(*priv), GFP_KERNEL);
119*4882a593Smuzhiyun 		if (priv == NULL)
120*4882a593Smuzhiyun 			return -ENOMEM;
121*4882a593Smuzhiyun 		*priv = *_priv;
122*4882a593Smuzhiyun 	} else {
123*4882a593Smuzhiyun 		priv = NULL;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	*ak = *temp;
126*4882a593Smuzhiyun 	ak->card = ice->card;
127*4882a593Smuzhiyun         ak->private_value[0] = (unsigned long)priv;
128*4882a593Smuzhiyun 	ak->private_data[0] = ice;
129*4882a593Smuzhiyun 	if (ak->ops.lock == NULL)
130*4882a593Smuzhiyun 		ak->ops.lock = snd_ice1712_akm4xxx_lock;
131*4882a593Smuzhiyun 	if (ak->ops.unlock == NULL)
132*4882a593Smuzhiyun 		ak->ops.unlock = snd_ice1712_akm4xxx_unlock;
133*4882a593Smuzhiyun 	if (ak->ops.write == NULL)
134*4882a593Smuzhiyun 		ak->ops.write = snd_ice1712_akm4xxx_write;
135*4882a593Smuzhiyun 	snd_akm4xxx_init(ak);
136*4882a593Smuzhiyun 	return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
snd_ice1712_akm4xxx_free(struct snd_ice1712 * ice)139*4882a593Smuzhiyun void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	unsigned int akidx;
142*4882a593Smuzhiyun 	if (ice->akm == NULL)
143*4882a593Smuzhiyun 		return;
144*4882a593Smuzhiyun 	for (akidx = 0; akidx < ice->akm_codecs; akidx++) {
145*4882a593Smuzhiyun 		struct snd_akm4xxx *ak = &ice->akm[akidx];
146*4882a593Smuzhiyun 		kfree((void*)ak->private_value[0]);
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 	kfree(ice->akm);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /*
152*4882a593Smuzhiyun  * build AK4xxx controls
153*4882a593Smuzhiyun  */
snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 * ice)154*4882a593Smuzhiyun int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	unsigned int akidx;
157*4882a593Smuzhiyun 	int err;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	for (akidx = 0; akidx < ice->akm_codecs; akidx++) {
160*4882a593Smuzhiyun 		struct snd_akm4xxx *ak = &ice->akm[akidx];
161*4882a593Smuzhiyun 		err = snd_akm4xxx_build_controls(ak);
162*4882a593Smuzhiyun 		if (err < 0)
163*4882a593Smuzhiyun 			return err;
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 	return 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ice1712_akm4xxx_init);
169*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ice1712_akm4xxx_free);
170*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls);
171