spicds.c revision 159689
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: head/sys/dev/sound/pci/spicds.c 159689 2006-06-17 15:11:36Z netchild $
27 */
28
29#include <dev/sound/pcm/sound.h>
30
31#include <dev/sound/pci/ak452x.h>
32
33MALLOC_DEFINE(M_AK452X, "ak452x", "ak452x codec");
34
35#define AK452X_NAMELEN	16
36struct 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
50static void
51ak452x_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
70static void
71ak452x_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
109struct ak452x_info *
110ak452x_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, 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
135void
136ak452x_destroy(struct ak452x_info *codec)
137{
138	snd_mtxfree(codec->lock);
139	free(codec, M_AK452X);
140}
141
142void
143ak452x_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
150void
151ak452x_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
158void
159ak452x_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
166void
167ak452x_setdvc(struct ak452x_info *codec, unsigned int dvc)
168{
169	snd_mtxlock(codec->lock);
170	codec->dvc = dvc;
171	snd_mtxunlock(codec->lock);
172}
173
174void
175ak452x_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
193void
194ak452x_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
207void
208ak452x_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
246MODULE_DEPEND(snd_ak452x, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
247MODULE_VERSION(snd_ak452x, 1);
248