FreeBSD kernel sound device code
spicds.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
5 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD$
30 */
31
32#ifdef HAVE_KERNEL_OPTION_HEADERS
33#include "opt_snd.h"
34#endif
35
36#include <dev/sound/pcm/sound.h>
37
39
40static MALLOC_DEFINE(M_SPICDS, "spicds", "SPI codec");
41
42#define SPICDS_NAMELEN 16
44 device_t dev;
46 void *devinfo;
47 int num; /* number of this device */
48 unsigned int type; /* codec type */
49 unsigned int cif; /* Controll data Interface Format (0/1) */
50 unsigned int format; /* data format and master clock frequency */
51 unsigned int dvc; /* De-emphasis and Volume Control */
52 unsigned int left, right;
54 struct mtx *lock;
55};
56
57static void
58spicds_wrbit(struct spicds_info *codec, int bit)
59{
60 unsigned int cs, cdti;
61 if (codec->cif)
62 cs = 1;
63 else
64 cs = 0;
65 if (bit)
66 cdti = 1;
67 else
68 cdti = 0;
69 codec->ctrl(codec->devinfo, cs, 0, cdti);
70 DELAY(1);
71 codec->ctrl(codec->devinfo, cs, 1, cdti);
72 DELAY(1);
73
74 return;
75}
76
77static void
78spicds_wrcd(struct spicds_info *codec, int reg, u_int16_t val)
79{
80 int mask;
81
82#if(0)
83 device_printf(codec->dev, "spicds_wrcd(codec, 0x%02x, 0x%02x)\n", reg, val);
84#endif
85 /* start */
86 if (codec->cif)
87 codec->ctrl(codec->devinfo, 1, 1, 0);
88 else
89 codec->ctrl(codec->devinfo, 0, 1, 0);
90 DELAY(1);
91 if (codec->type != SPICDS_TYPE_WM8770) {
92 if (codec->type == SPICDS_TYPE_AK4381) {
93 /* AK4381 chip address */
94 spicds_wrbit(codec, 0);
95 spicds_wrbit(codec, 1);
96 }
97 else if (codec->type == SPICDS_TYPE_AK4396)
98 {
99 /* AK4396 chip address */
100 spicds_wrbit(codec, 0);
101 spicds_wrbit(codec, 0);
102 }
103 else {
104 /* chip address */
105 spicds_wrbit(codec, 1);
106 spicds_wrbit(codec, 0);
107 }
108 /* write */
109 spicds_wrbit(codec, 1);
110 /* register address */
111 for (mask = 0x10; mask != 0; mask >>= 1)
112 spicds_wrbit(codec, reg & mask);
113 /* data */
114 for (mask = 0x80; mask != 0; mask >>= 1)
115 spicds_wrbit(codec, val & mask);
116 /* stop */
117 DELAY(1);
118 }
119 else {
120 /* register address */
121 for (mask = 0x40; mask != 0; mask >>= 1)
122 spicds_wrbit(codec, reg & mask);
123 /* data */
124 for (mask = 0x100; mask != 0; mask >>= 1)
125 spicds_wrbit(codec, val & mask);
126 /* stop */
127 DELAY(1);
128 }
129 if (codec->cif) {
130 codec->ctrl(codec->devinfo, 0, 1, 0);
131 DELAY(1);
132 codec->ctrl(codec->devinfo, 1, 1, 0);
133 }
134 else {
135 codec->ctrl(codec->devinfo, 1, 1, 0);
136 }
137
138 return;
139}
140
141struct spicds_info *
143{
144 struct spicds_info *codec;
145
146#if(0)
147 device_printf(dev, "spicds_create(dev, devinfo, %d, ctrl)\n", num);
148#endif
149 codec = (struct spicds_info *)malloc(sizeof *codec, M_SPICDS, M_NOWAIT);
150 if (codec == NULL)
151 return NULL;
152
153 snprintf(codec->name, SPICDS_NAMELEN, "%s:spicds%d", device_get_nameunit(dev), num);
154 codec->lock = snd_mtxcreate(codec->name, codec->name);
155 codec->dev = dev;
156 codec->ctrl = ctrl;
157 codec->devinfo = devinfo;
158 codec->num = num;
159 codec->type = SPICDS_TYPE_AK4524;
160 codec->cif = 0;
163
164 return codec;
165}
166
167void
169{
170 snd_mtxfree(codec->lock);
171 free(codec, M_SPICDS);
172}
173
174void
175spicds_settype(struct spicds_info *codec, unsigned int type)
176{
177 snd_mtxlock(codec->lock);
178 codec->type = type;
179 snd_mtxunlock(codec->lock);
180}
181
182void
183spicds_setcif(struct spicds_info *codec, unsigned int cif)
184{
185 snd_mtxlock(codec->lock);
186 codec->cif = cif;
187 snd_mtxunlock(codec->lock);
188}
189
190void
191spicds_setformat(struct spicds_info *codec, unsigned int format)
192{
193 snd_mtxlock(codec->lock);
194 codec->format = format;
195 snd_mtxunlock(codec->lock);
196}
197
198void
199spicds_setdvc(struct spicds_info *codec, unsigned int dvc)
200{
201 snd_mtxlock(codec->lock);
202 codec->dvc = dvc;
203 snd_mtxunlock(codec->lock);
204}
205
206void
208{
209#if(0)
210 device_printf(codec->dev, "spicds_init(codec)\n");
211#endif
212 snd_mtxlock(codec->lock);
213 if (codec->type == SPICDS_TYPE_AK4524 ||\
214 codec->type == SPICDS_TYPE_AK4528) {
215 /* power off */
216 spicds_wrcd(codec, AK4524_POWER, 0);
217 /* set parameter */
218 spicds_wrcd(codec, AK4524_FORMAT, codec->format);
219 spicds_wrcd(codec, AK4524_DVC, codec->dvc);
220 /* power on */
223 /* free reset register */
226 }
227 if (codec->type == SPICDS_TYPE_WM8770) {
228 /* WM8770 init values are taken from ALSA */
229
230 /* These come first to reduce init pop noise */
231 spicds_wrcd(codec, 0x1b, 0x044); /* ADC Mux (AC'97 source) */
232 spicds_wrcd(codec, 0x1c, 0x00B); /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
233 spicds_wrcd(codec, 0x1d, 0x009); /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
234
235 spicds_wrcd(codec, 0x18, 0x000); /* All power-up */
236
237 spicds_wrcd(codec, 0x16, 0x122); /* I2S, normal polarity, 24bit */
238 spicds_wrcd(codec, 0x17, 0x022); /* 256fs, slave mode */
239
240 spicds_wrcd(codec, 0x19, 0x000); /* -12dB ADC/L */
241 spicds_wrcd(codec, 0x1a, 0x000); /* -12dB ADC/R */
242 }
243 if (codec->type == SPICDS_TYPE_AK4358)
244 spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */
245 if (codec->type == SPICDS_TYPE_AK4381)
246 spicds_wrcd(codec, 0x00, 0x8f); /* I2S, 24bit, power-up */
247 if (codec->type == SPICDS_TYPE_AK4396)
248 spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */
249 snd_mtxunlock(codec->lock);
250}
251
252void
254{
255 snd_mtxlock(codec->lock);
256 if (codec->type != SPICDS_TYPE_WM8770) {
257 /* reset */
258 spicds_wrcd(codec, AK4524_RESET, 0);
259 /* set parameter */
260 spicds_wrcd(codec, AK4524_FORMAT, codec->format);
261 spicds_wrcd(codec, AK4524_DVC, codec->dvc);
262 /* free reset register */
265 } else {
266 /* WM8770 reinit */
267 /* AK4358 reinit */
268 /* AK4381 reinit */
269 }
270 snd_mtxunlock(codec->lock);
271}
272
273void
274spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int right)
275{
276#if(0)
277 device_printf(codec->dev, "spicds_set(codec, %d, %d, %d)\n", dir, left, right);
278#endif
279 snd_mtxlock(codec->lock);
280 if (left >= 100)
281 if ((codec->type == SPICDS_TYPE_AK4381) || \
282 (codec->type == SPICDS_TYPE_AK4396))
283 left = 255;
284 else
285 left = 127;
286 else
287 switch (codec->type) {
289 left = left + 27;
290 break;
293 left = left * 255 / 100;
294 break;
295 default:
296 left = left * 127 / 100;
297 }
298 if (right >= 100)
299 if ((codec->type == SPICDS_TYPE_AK4381) || \
300 (codec->type == SPICDS_TYPE_AK4396))
301 right = 255;
302 else
303 right = 127;
304 else
305 switch (codec->type) {
307 right = right + 27;
308 break;
311 right = right * 255 / 100;
312 break;
313 default:
314 right = right * 127 / 100;
315 }
316 if (dir == PCMDIR_REC && codec->type == SPICDS_TYPE_AK4524) {
317#if(0)
318 device_printf(codec->dev, "spicds_set(): AK4524(REC) %d/%d\n", left, right);
319#endif
322 }
323 if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4524) {
324#if(0)
325 device_printf(codec->dev, "spicds_set(): AK4524(PLAY) %d/%d\n", left, right);
326#endif
329 }
330 if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4528) {
331#if(0)
332 device_printf(codec->dev, "spicds_set(): AK4528(PLAY) %d/%d\n", left, right);
333#endif
336 }
337 if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_WM8770) {
338#if(0)
339 device_printf(codec->dev, "spicds_set(): WM8770(PLAY) %d/%d\n", left, right);
340#endif
343 }
344 if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4358) {
345#if(0)
346 device_printf(codec->dev, "spicds_set(): AK4358(PLAY) %d/%d\n", left, right);
347#endif
350 }
351 if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4381) {
352#if(0)
353 device_printf(codec->dev, "spicds_set(): AK4381(PLAY) %d/%d\n", left, right);
354#endif
357 }
358
359 if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4396) {
360#if(0)
361 device_printf(codec->dev, "spicds_set(): AK4396(PLAY) %d/%d\n", left, right);
362#endif
365 }
366
367 snd_mtxunlock(codec->lock);
368}
369
371MODULE_VERSION(snd_spicds, 1);
void * devinfo
Definition: ac97_if.m:47
uint32_t format
Definition: audio_dai_if.m:39
#define PCMDIR_PLAY
Definition: channel.h:339
#define PCMDIR_REC
Definition: channel.h:341
METHOD int free
Definition: channel_if.m:110
int type
Definition: dsp.c:386
unsigned right
Definition: es137x.c:261
unsigned left
Definition: es137x.c:260
uint8_t mask
Definition: hdac.c:212
uint8_t reg
Definition: hdac.c:211
int dir
Definition: hdac_if.m:45
unsigned dev
Definition: mixer_if.m:59
u_int32_t val
void * snd_mtxcreate(const char *desc, const char *type)
Definition: sound.c:88
void snd_mtxfree(void *m)
Definition: sound.c:98
#define SOUND_PREFVER
Definition: sound.h:103
#define SOUND_MAXVER
Definition: sound.h:104
#define snd_mtxlock(m)
Definition: sound.h:347
#define snd_mtxunlock(m)
Definition: sound.h:348
#define SOUND_MINVER
Definition: sound.h:102
static void spicds_wrbit(struct spicds_info *codec, int bit)
Definition: spicds.c:58
void spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int right)
Definition: spicds.c:274
void spicds_setdvc(struct spicds_info *codec, unsigned int dvc)
Definition: spicds.c:199
void spicds_settype(struct spicds_info *codec, unsigned int type)
Definition: spicds.c:175
void spicds_setformat(struct spicds_info *codec, unsigned int format)
Definition: spicds.c:191
void spicds_reinit(struct spicds_info *codec)
Definition: spicds.c:253
#define SPICDS_NAMELEN
Definition: spicds.c:42
struct spicds_info * spicds_create(device_t dev, void *devinfo, int num, spicds_ctrl ctrl)
Definition: spicds.c:142
void spicds_init(struct spicds_info *codec)
Definition: spicds.c:207
static MALLOC_DEFINE(M_SPICDS, "spicds", "SPI codec")
MODULE_VERSION(snd_spicds, 1)
void spicds_setcif(struct spicds_info *codec, unsigned int cif)
Definition: spicds.c:183
MODULE_DEPEND(snd_spicds, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER)
static void spicds_wrcd(struct spicds_info *codec, int reg, u_int16_t val)
Definition: spicds.c:78
void spicds_destroy(struct spicds_info *codec)
Definition: spicds.c:168
#define WM8770_AOATT_UPDATE
Definition: spicds.h:96
#define AK452X_POWER_PWVR
Definition: spicds.h:45
#define WM8770_AOATT_R1
Definition: spicds.h:88
#define AK452X_FORMAT_256FSN
Definition: spicds.h:56
#define AK4396_LOATT
Definition: spicds.h:108
#define AK4524_RIPGA
Definition: spicds.h:80
#define AK452X_RESET_RSAD
Definition: spicds.h:49
#define AK4524_RESET
Definition: spicds.h:46
#define SPICDS_TYPE_AK4528
Definition: spicds.h:34
#define WM8770_AOATT_L1
Definition: spicds.h:87
#define AK4396_ROATT
Definition: spicds.h:109
#define AK4524_FORMAT
Definition: spicds.h:50
#define SPICDS_TYPE_AK4381
Definition: spicds.h:37
#define AK452X_DVC_ZCE
Definition: spicds.h:75
#define AK4524_ROATT
Definition: spicds.h:82
#define AK4358_OATT_ENABLE
Definition: spicds.h:101
#define AK4528_ROATT
Definition: spicds.h:84
#define SPICDS_TYPE_WM8770
Definition: spicds.h:35
#define AK4524_LOATT
Definition: spicds.h:81
#define AK4524_LIPGA
Definition: spicds.h:79
#define AK4524_DVC
Definition: spicds.h:66
#define SPICDS_TYPE_AK4358
Definition: spicds.h:36
#define AK452X_RESET_RSDA
Definition: spicds.h:48
#define AK452X_POWER_PWDA
Definition: spicds.h:43
#define AK4381_LOATT
Definition: spicds.h:104
void(* spicds_ctrl)(void *, unsigned int, unsigned int, unsigned int)
Definition: spicds.h:113
#define AK452X_DVC_ZTM1024
Definition: spicds.h:73
#define AK4358_RO1ATT
Definition: spicds.h:100
#define AK452X_DVC_DEMOFF
Definition: spicds.h:68
#define AK4358_LO1ATT
Definition: spicds.h:99
#define AK452X_FORMAT_1X
Definition: spicds.h:52
#define SPICDS_TYPE_AK4524
Definition: spicds.h:33
#define SPICDS_TYPE_AK4396
Definition: spicds.h:38
#define AK4381_ROATT
Definition: spicds.h:105
#define AK452X_FORMAT_I2S
Definition: spicds.h:64
#define AK4524_POWER
Definition: spicds.h:41
#define AK452X_POWER_PWAD
Definition: spicds.h:44
#define AK4528_LOATT
Definition: spicds.h:83
unsigned int type
Definition: spicds.c:48
unsigned int right
Definition: spicds.c:52
struct mtx * lock
Definition: spicds.c:54
int num
Definition: spicds.c:47
void * devinfo
Definition: spicds.c:46
device_t dev
Definition: spicds.c:44
char name[SPICDS_NAMELEN]
Definition: spicds.c:53
unsigned int format
Definition: spicds.c:50
spicds_ctrl ctrl
Definition: spicds.c:45
unsigned int dvc
Definition: spicds.c:51
unsigned int left
Definition: spicds.c:52
unsigned int cif
Definition: spicds.c:49