xref: /freebsd/sys/dev/sound/pci/spicds.c (revision 12ab72d3)
1 /*
2  * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <dev/sound/pcm/sound.h>
30 
31 #include <dev/sound/pci/ak452x.h>
32 
33 MALLOC_DEFINE(M_AK452X, "ak452x", "ak452x codec");
34 
35 #define AK452X_NAMELEN	16
36 struct ak452x_info {
37 	device_t dev;
38 	ak452x_ctrl ctrl;
39 	void *devinfo;
40 	int num; /* number of this device */
41 	unsigned int type;   /* codec type */
42 	unsigned int cif;    /* Controll data Interface Format (0/1) */
43 	unsigned int format; /* data format and master clock frequency */
44 	unsigned int dvc;    /* De-emphasis and Volume Control */
45 	unsigned int left, right;
46 	char name[AK452X_NAMELEN];
47 	void *lock;
48 };
49 
50 static void
51 ak452x_wrbit(struct ak452x_info *codec, int bit)
52 {
53 	unsigned int cs, cdti;
54 	if (codec->cif)
55 		cs = 1;
56 	else
57 		cs = 0;
58 	if (bit)
59 		cdti = 1;
60 	else
61 		cdti = 0;
62 	codec->ctrl(codec->devinfo, cs, 0, cdti);
63 	DELAY(1);
64 	codec->ctrl(codec->devinfo, cs, 1, cdti);
65 	DELAY(1);
66 
67 	return;
68 }
69 
70 static void
71 ak452x_wrcd(struct ak452x_info *codec, int reg, u_int8_t val)
72 {
73 	int mask;
74 
75 #if(0)
76 	device_printf(codec->dev, "ak452x_wrcd(codec, 0x%02x, 0x%02x)\n", reg, val);
77 #endif
78 	/* start */
79 	if (codec->cif)
80 		codec->ctrl(codec->devinfo, 1, 1, 0);
81 	else
82 		codec->ctrl(codec->devinfo, 0, 1, 0);
83 	DELAY(1);
84 	/* chip address */
85 	ak452x_wrbit(codec, 1);
86 	ak452x_wrbit(codec, 0);
87 	/* write */
88 	ak452x_wrbit(codec, 1);
89 	/* register address */
90 	for (mask = 0x10; mask != 0; mask >>= 1)
91 		ak452x_wrbit(codec, reg & mask);
92 	/* data */
93 	for (mask = 0x80; mask != 0; mask >>= 1)
94 		ak452x_wrbit(codec, val & mask);
95 	/* stop */
96 	DELAY(1);
97 	if (codec->cif) {
98 		codec->ctrl(codec->devinfo, 0, 1, 0);
99 		DELAY(1);
100 		codec->ctrl(codec->devinfo, 1, 1, 0);
101 	}
102 	else {
103 		codec->ctrl(codec->devinfo, 1, 1, 0);
104 	}
105 
106 	return;
107 }
108 
109 struct ak452x_info *
110 ak452x_create(device_t dev, void *devinfo, int num, ak452x_ctrl ctrl)
111 {
112 	struct ak452x_info *codec;
113 
114 #if(0)
115 	device_printf(dev, "ak452x_create(dev, devinfo, %d, ctrl)\n", num);
116 #endif
117 	codec = (struct ak452x_info *)malloc(sizeof *codec, M_AK452X, M_NOWAIT);
118 	if (codec == NULL)
119 		return NULL;
120 
121 	snprintf(codec->name, AK452X_NAMELEN, "%s:ak452x%d", device_get_nameunit(dev), num);
122 	codec->lock = snd_mtxcreate(codec->name);
123 	codec->dev = dev;
124 	codec->ctrl = ctrl;
125 	codec->devinfo = devinfo;
126 	codec->num = num;
127 	codec->type = AK452X_TYPE_4524;
128 	codec->cif = 0;
129 	codec->format = AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X;
130 	codec->dvc = AK452X_DVC_DEMOFF | AK452X_DVC_ZTM1024 | AK452X_DVC_ZCE;
131 
132 	return codec;
133 }
134 
135 void
136 ak452x_destroy(struct ak452x_info *codec)
137 {
138 	snd_mtxfree(codec->lock);
139 	free(codec, M_AK452X);
140 }
141 
142 void
143 ak452x_settype(struct ak452x_info *codec, unsigned int type)
144 {
145 	snd_mtxlock(codec->lock);
146 	codec->type = type;
147 	snd_mtxunlock(codec->lock);
148 }
149 
150 void
151 ak452x_setcif(struct ak452x_info *codec, unsigned int cif)
152 {
153 	snd_mtxlock(codec->lock);
154 	codec->cif = cif;
155 	snd_mtxunlock(codec->lock);
156 }
157 
158 void
159 ak452x_setformat(struct ak452x_info *codec, unsigned int format)
160 {
161 	snd_mtxlock(codec->lock);
162 	codec->format = format;
163 	snd_mtxunlock(codec->lock);
164 }
165 
166 void
167 ak452x_setdvc(struct ak452x_info *codec, unsigned int dvc)
168 {
169 	snd_mtxlock(codec->lock);
170 	codec->type = dvc;
171 	snd_mtxunlock(codec->lock);
172 }
173 
174 void
175 ak452x_init(struct ak452x_info *codec)
176 {
177 #if(0)
178 	device_printf(codec->dev, "ak452x_init(codec)\n");
179 #endif
180 	snd_mtxlock(codec->lock);
181 	/* power off */
182 	ak452x_wrcd(codec, AK4524_POWER, 0);
183 	/* set parameter */
184 	ak452x_wrcd(codec, AK4524_FORMAT, codec->format);
185 	ak452x_wrcd(codec, AK4524_DVC, codec->dvc);
186 	/* power on */
187 	ak452x_wrcd(codec, AK4524_POWER, AK452X_POWER_PWDA | AK452X_POWER_PWAD | AK452X_POWER_PWVR);
188 	/* free reset register */
189 	ak452x_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD);
190 	snd_mtxunlock(codec->lock);
191 }
192 
193 void
194 ak452x_reinit(struct ak452x_info *codec)
195 {
196 	snd_mtxlock(codec->lock);
197 	/* reset */
198 	ak452x_wrcd(codec, AK4524_RESET, 0);
199 	/* set parameter */
200 	ak452x_wrcd(codec, AK4524_FORMAT, codec->format);
201 	ak452x_wrcd(codec, AK4524_DVC, codec->dvc);
202 	/* free reset register */
203 	ak452x_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD);
204 	snd_mtxunlock(codec->lock);
205 }
206 
207 void
208 ak452x_set(struct ak452x_info *codec, int dir, unsigned int left, unsigned int right)
209 {
210 #if(0)
211 	device_printf(codec->dev, "ak452x_set(codec, %d, %d, %d)\n", dir, left, right);
212 #endif
213 	snd_mtxlock(codec->lock);
214 	if (left >= 100)
215 		left  = 127;
216 	else
217 		left = left * 127 / 100;
218 	if (right >= 100)
219 		right  = 127;
220 	else
221 		right = right * 127 / 100;
222 	if (dir == PCMDIR_REC && codec->type == AK452X_TYPE_4524) {
223 #if(0)
224 		device_printf(codec->dev, "ak452x_set(): AK4524(REC) %d/%d\n", left, right);
225 #endif
226 		ak452x_wrcd(codec, AK4524_LIPGA, left);
227 		ak452x_wrcd(codec, AK4524_RIPGA, right);
228 	}
229 	if (dir == PCMDIR_PLAY && codec->type == AK452X_TYPE_4524) {
230 #if(0)
231 		device_printf(codec->dev, "ak452x_set(): AK4524(PLAY) %d/%d\n", left, right);
232 #endif
233 		ak452x_wrcd(codec, AK4524_LOATT, left);
234 		ak452x_wrcd(codec, AK4524_ROATT, right);
235 	}
236 	if (dir == PCMDIR_PLAY && codec->type == AK452X_TYPE_4528) {
237 #if(0)
238 		device_printf(codec->dev, "ak452x_set(): AK4528(PLAY) %d/%d\n", left, right);
239 #endif
240 		ak452x_wrcd(codec, AK4528_LOATT, left);
241 		ak452x_wrcd(codec, AK4528_ROATT, right);
242 	}
243 	snd_mtxunlock(codec->lock);
244 }
245 
246 MODULE_DEPEND(snd_ak452x, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
247 MODULE_VERSION(snd_ak452x, 1);
248