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