2 * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
3 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
27 * $FreeBSD: src/sys/dev/sound/pci/spicds.c,v 1.5.2.2 2007/06/11 19:33:27 ariff Exp $
28 * $DragonFly: src/sys/dev/sound/pci/spicds.c,v 1.3 2007/06/27 13:26:18 hasso Exp $
31 #include <dev/sound/pcm/sound.h>
33 #include <dev/sound/pci/spicds.h>
35 MALLOC_DEFINE(M_SPICDS
, "spicds", "SPI codec");
37 #define SPICDS_NAMELEN 16
42 int num
; /* number of this device */
43 unsigned int type
; /* codec type */
44 unsigned int cif
; /* Controll data Interface Format (0/1) */
45 unsigned int format
; /* data format and master clock frequency */
46 unsigned int dvc
; /* De-emphasis and Volume Control */
47 unsigned int left
, right
;
48 char name
[SPICDS_NAMELEN
];
53 spicds_wrbit(struct spicds_info
*codec
, int bit
)
55 unsigned int cs
, cdti
;
64 codec
->ctrl(codec
->devinfo
, cs
, 0, cdti
);
66 codec
->ctrl(codec
->devinfo
, cs
, 1, cdti
);
73 spicds_wrcd(struct spicds_info
*codec
, int reg
, u_int16_t val
)
78 device_printf(codec
->dev
, "spicds_wrcd(codec, 0x%02x, 0x%02x)\n", reg
, val
);
82 codec
->ctrl(codec
->devinfo
, 1, 1, 0);
84 codec
->ctrl(codec
->devinfo
, 0, 1, 0);
86 if (codec
->type
!= SPICDS_TYPE_WM8770
) {
87 if (codec
->type
== SPICDS_TYPE_AK4381
) {
88 /* AK4381 chip address */
89 spicds_wrbit(codec
, 0);
90 spicds_wrbit(codec
, 1);
92 else if (codec
->type
== SPICDS_TYPE_AK4396
)
94 /* AK4396 chip address */
95 spicds_wrbit(codec
, 0);
96 spicds_wrbit(codec
, 0);
100 spicds_wrbit(codec
, 1);
101 spicds_wrbit(codec
, 0);
104 spicds_wrbit(codec
, 1);
105 /* register address */
106 for (mask
= 0x10; mask
!= 0; mask
>>= 1)
107 spicds_wrbit(codec
, reg
& mask
);
109 for (mask
= 0x80; mask
!= 0; mask
>>= 1)
110 spicds_wrbit(codec
, val
& mask
);
115 /* register address */
116 for (mask
= 0x40; mask
!= 0; mask
>>= 1)
117 spicds_wrbit(codec
, reg
& mask
);
119 for (mask
= 0x100; mask
!= 0; mask
>>= 1)
120 spicds_wrbit(codec
, val
& mask
);
125 codec
->ctrl(codec
->devinfo
, 0, 1, 0);
127 codec
->ctrl(codec
->devinfo
, 1, 1, 0);
130 codec
->ctrl(codec
->devinfo
, 1, 1, 0);
137 spicds_create(device_t dev
, void *devinfo
, int num
, spicds_ctrl ctrl
)
139 struct spicds_info
*codec
;
142 device_printf(dev
, "spicds_create(dev, devinfo, %d, ctrl)\n", num
);
144 codec
= (struct spicds_info
*)kmalloc(sizeof *codec
, M_SPICDS
, M_NOWAIT
);
148 ksnprintf(codec
->name
, SPICDS_NAMELEN
, "%s:spicds%d", device_get_nameunit(dev
), num
);
149 codec
->lock
= snd_mtxcreate(codec
->name
, codec
->name
);
152 codec
->devinfo
= devinfo
;
154 codec
->type
= SPICDS_TYPE_AK4524
;
156 codec
->format
= AK452X_FORMAT_I2S
| AK452X_FORMAT_256FSN
| AK452X_FORMAT_1X
;
157 codec
->dvc
= AK452X_DVC_DEMOFF
| AK452X_DVC_ZTM1024
| AK452X_DVC_ZCE
;
163 spicds_destroy(struct spicds_info
*codec
)
165 snd_mtxfree(codec
->lock
);
166 kfree(codec
, M_SPICDS
);
170 spicds_settype(struct spicds_info
*codec
, unsigned int type
)
172 snd_mtxlock(codec
->lock
);
174 snd_mtxunlock(codec
->lock
);
178 spicds_setcif(struct spicds_info
*codec
, unsigned int cif
)
180 snd_mtxlock(codec
->lock
);
182 snd_mtxunlock(codec
->lock
);
186 spicds_setformat(struct spicds_info
*codec
, unsigned int format
)
188 snd_mtxlock(codec
->lock
);
189 codec
->format
= format
;
190 snd_mtxunlock(codec
->lock
);
194 spicds_setdvc(struct spicds_info
*codec
, unsigned int dvc
)
196 snd_mtxlock(codec
->lock
);
198 snd_mtxunlock(codec
->lock
);
202 spicds_init(struct spicds_info
*codec
)
205 device_printf(codec
->dev
, "spicds_init(codec)\n");
207 snd_mtxlock(codec
->lock
);
208 if (codec
->type
== SPICDS_TYPE_AK4524
||\
209 codec
->type
== SPICDS_TYPE_AK4528
) {
211 spicds_wrcd(codec
, AK4524_POWER
, 0);
213 spicds_wrcd(codec
, AK4524_FORMAT
, codec
->format
);
214 spicds_wrcd(codec
, AK4524_DVC
, codec
->dvc
);
216 spicds_wrcd(codec
, AK4524_POWER
, AK452X_POWER_PWDA
| AK452X_POWER_PWAD
| AK452X_POWER_PWVR
);
217 /* free reset register */
218 spicds_wrcd(codec
, AK4524_RESET
, AK452X_RESET_RSDA
| AK452X_RESET_RSAD
);
220 if (codec
->type
== SPICDS_TYPE_WM8770
) {
221 /* WM8770 init values are taken from ALSA */
222 /* These come first to reduce init pop noise */
223 spicds_wrcd(codec
, 0x1b, 0x044); /* ADC Mux (AC'97 source) */
224 spicds_wrcd(codec
, 0x1c, 0x00B); /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
225 spicds_wrcd(codec
, 0x1d, 0x009); /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
227 spicds_wrcd(codec
, 0x18, 0x000); /* All power-up */
229 spicds_wrcd(codec
, 0x16, 0x122); /* I2S, normal polarity, 24bit */
230 spicds_wrcd(codec
, 0x17, 0x022); /* 256fs, slave mode */
232 spicds_wrcd(codec
, 0x19, 0x000); /* -12dB ADC/L */
233 spicds_wrcd(codec
, 0x1a, 0x000); /* -12dB ADC/R */
235 if (codec
->type
== SPICDS_TYPE_AK4358
)
236 spicds_wrcd(codec
, 0x00, 0x07); /* I2S, 24bit, power-up */
237 if (codec
->type
== SPICDS_TYPE_AK4381
)
238 spicds_wrcd(codec
, 0x00, 0x0f); /* I2S, 24bit, power-up */
239 if (codec
->type
== SPICDS_TYPE_AK4396
)
240 spicds_wrcd(codec
, 0x00, 0x07); /* I2S, 24bit, power-up */
241 snd_mtxunlock(codec
->lock
);
245 spicds_reinit(struct spicds_info
*codec
)
247 snd_mtxlock(codec
->lock
);
248 if (codec
->type
!= SPICDS_TYPE_WM8770
) {
250 spicds_wrcd(codec
, AK4524_RESET
, 0);
252 spicds_wrcd(codec
, AK4524_FORMAT
, codec
->format
);
253 spicds_wrcd(codec
, AK4524_DVC
, codec
->dvc
);
254 /* free reset register */
255 spicds_wrcd(codec
, AK4524_RESET
, AK452X_RESET_RSDA
| AK452X_RESET_RSAD
);
262 snd_mtxunlock(codec
->lock
);
266 spicds_set(struct spicds_info
*codec
, int dir
, unsigned int left
, unsigned int right
)
269 device_printf(codec
->dev
, "spicds_set(codec, %d, %d, %d)\n", dir
, left
, right
);
271 snd_mtxlock(codec
->lock
);
273 if ((codec
->type
== SPICDS_TYPE_AK4381
) || \
274 (codec
->type
== SPICDS_TYPE_AK4396
))
279 switch (codec
->type
) {
280 case SPICDS_TYPE_WM8770
:
283 case SPICDS_TYPE_AK4381
|| SPICDS_TYPE_AK4396
:
284 left
= left
* 255 / 100;
287 left
= left
* 127 / 100;
290 if ((codec
->type
== SPICDS_TYPE_AK4381
) || \
291 (codec
->type
== SPICDS_TYPE_AK4396
))
296 switch (codec
->type
) {
297 case SPICDS_TYPE_WM8770
:
300 case SPICDS_TYPE_AK4381
|| SPICDS_TYPE_AK4396
:
301 right
= right
* 255 / 100;
304 right
= right
* 127 / 100;
306 if (dir
== PCMDIR_REC
&& codec
->type
== SPICDS_TYPE_AK4524
) {
308 device_printf(codec
->dev
, "spicds_set(): AK4524(REC) %d/%d\n", left
, right
);
310 spicds_wrcd(codec
, AK4524_LIPGA
, left
);
311 spicds_wrcd(codec
, AK4524_RIPGA
, right
);
313 if (dir
== PCMDIR_PLAY
&& codec
->type
== SPICDS_TYPE_AK4524
) {
315 device_printf(codec
->dev
, "spicds_set(): AK4524(PLAY) %d/%d\n", left
, right
);
317 spicds_wrcd(codec
, AK4524_LOATT
, left
);
318 spicds_wrcd(codec
, AK4524_ROATT
, right
);
320 if (dir
== PCMDIR_PLAY
&& codec
->type
== SPICDS_TYPE_AK4528
) {
322 device_printf(codec
->dev
, "spicds_set(): AK4528(PLAY) %d/%d\n", left
, right
);
324 spicds_wrcd(codec
, AK4528_LOATT
, left
);
325 spicds_wrcd(codec
, AK4528_ROATT
, right
);
327 if (dir
== PCMDIR_PLAY
&& codec
->type
== SPICDS_TYPE_WM8770
) {
329 device_printf(codec
->dev
, "spicds_set(): WM8770(PLAY) %d/%d\n", left
, right
);
331 spicds_wrcd(codec
, WM8770_AOATT_L1
, left
| WM8770_AOATT_UPDATE
);
332 spicds_wrcd(codec
, WM8770_AOATT_R1
, right
| WM8770_AOATT_UPDATE
);
334 if (dir
== PCMDIR_PLAY
&& codec
->type
== SPICDS_TYPE_AK4358
) {
336 device_printf(codec
->dev
, "spicds_set(): AK4358(PLAY) %d/%d\n", left
, right
);
338 spicds_wrcd(codec
, AK4358_LO1ATT
, left
| AK4358_OATT_ENABLE
);
339 spicds_wrcd(codec
, AK4358_RO1ATT
, right
| AK4358_OATT_ENABLE
);
341 if (dir
== PCMDIR_PLAY
&& codec
->type
== SPICDS_TYPE_AK4381
) {
343 device_printf(codec
->dev
, "spicds_set(): AK4381(PLAY) %d/%d\n", left
, right
);
345 spicds_wrcd(codec
, AK4381_LOATT
, left
);
346 spicds_wrcd(codec
, AK4381_ROATT
, right
);
349 if (dir
== PCMDIR_PLAY
&& codec
->type
== SPICDS_TYPE_AK4396
) {
351 device_printf(codec
->dev
, "spicds_set(): AK4396(PLAY) %d/%d\n", left
, right
);
353 spicds_wrcd(codec
, AK4396_LOATT
, left
);
354 spicds_wrcd(codec
, AK4396_ROATT
, right
);
357 snd_mtxunlock(codec
->lock
);
360 MODULE_DEPEND(snd_spicds
, sound
, SOUND_MINVER
, SOUND_PREFVER
, SOUND_MAXVER
);
361 MODULE_VERSION(snd_spicds
, 1);