1*cfc80c6fSisaki /* $NetBSD: mavb.c,v 1.14 2019/06/07 13:24:21 isaki Exp $ */
2845cd29dSjmcneill /* $OpenBSD: mavb.c,v 1.6 2005/04/15 13:05:14 mickey Exp $ */
3845cd29dSjmcneill
4845cd29dSjmcneill /*
5845cd29dSjmcneill * Copyright (c) 2005 Mark Kettenis
6845cd29dSjmcneill *
7845cd29dSjmcneill * Permission to use, copy, modify, and distribute this software for any
8845cd29dSjmcneill * purpose with or without fee is hereby granted, provided that the above
9845cd29dSjmcneill * copyright notice and this permission notice appear in all copies.
10845cd29dSjmcneill *
11845cd29dSjmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12845cd29dSjmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13845cd29dSjmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14845cd29dSjmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15845cd29dSjmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16845cd29dSjmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17845cd29dSjmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18845cd29dSjmcneill */
19845cd29dSjmcneill
20845cd29dSjmcneill #include <sys/param.h>
21845cd29dSjmcneill #include <sys/systm.h>
22845cd29dSjmcneill #include <sys/device.h>
23845cd29dSjmcneill #include <sys/kernel.h>
248a962f23Sjmcneill #include <sys/kmem.h>
25845cd29dSjmcneill #include <sys/callout.h>
26845cd29dSjmcneill
27cf10107dSdyoung #include <sys/bus.h>
28845cd29dSjmcneill #include <machine/intr.h>
29845cd29dSjmcneill #include <machine/autoconf.h>
30845cd29dSjmcneill
31845cd29dSjmcneill #include <sys/audioio.h>
32e622eac4Sisaki #include <dev/audio/audio_if.h>
33845cd29dSjmcneill
34845cd29dSjmcneill #include <arch/sgimips/mace/macevar.h>
35845cd29dSjmcneill #include <arch/sgimips/mace/macereg.h>
36845cd29dSjmcneill #include <arch/sgimips/mace/mavbreg.h>
37845cd29dSjmcneill
38845cd29dSjmcneill #include <dev/ic/ad1843reg.h>
39845cd29dSjmcneill
40845cd29dSjmcneill #undef MAVB_DEBUG
41845cd29dSjmcneill
42845cd29dSjmcneill #ifdef MAVB_DEBUG
43845cd29dSjmcneill #define DPRINTF(l,x) do { if (mavb_debug & (l)) printf x; } while (0)
44845cd29dSjmcneill #define MAVB_DEBUG_INTR 0x0100
45845cd29dSjmcneill int mavb_debug = ~MAVB_DEBUG_INTR;
46845cd29dSjmcneill #else
47845cd29dSjmcneill #define DPRINTF(l,x) /* nothing */
48845cd29dSjmcneill #endif
49845cd29dSjmcneill
50845cd29dSjmcneill /* Repeat delays for volume buttons. */
51845cd29dSjmcneill #define MAVB_VOLUME_BUTTON_REPEAT_DEL1 400 /* 400ms to start repeating */
52845cd29dSjmcneill #define MAVB_VOLUME_BUTTON_REPEAT_DELN 100 /* 100ms between repeats */
53845cd29dSjmcneill
54845cd29dSjmcneill /* XXX We need access to some of the MACE ISA registers. */
55845cd29dSjmcneill #define MAVB_ISA_NREGS 0x20
56845cd29dSjmcneill
57845cd29dSjmcneill /*
58845cd29dSjmcneill * AD1843 Mixer.
59845cd29dSjmcneill */
60845cd29dSjmcneill
61845cd29dSjmcneill enum {
62845cd29dSjmcneill AD1843_RECORD_CLASS,
63845cd29dSjmcneill AD1843_ADC_SOURCE, /* ADC Source Select */
64845cd29dSjmcneill AD1843_ADC_GAIN, /* ADC Input Gain */
65845cd29dSjmcneill
66845cd29dSjmcneill AD1843_INPUT_CLASS,
67845cd29dSjmcneill AD1843_DAC1_GAIN, /* DAC1 Analog/Digital Gain/Attenuation */
68845cd29dSjmcneill AD1843_DAC1_MUTE, /* DAC1 Analog Mute */
69845cd29dSjmcneill AD1843_DAC2_GAIN, /* DAC2 Mix Gain */
70845cd29dSjmcneill AD1843_AUX1_GAIN, /* Auxilliary 1 Mix Gain */
71845cd29dSjmcneill AD1843_AUX2_GAIN, /* Auxilliary 2 Mix Gain */
72845cd29dSjmcneill AD1843_AUX3_GAIN, /* Auxilliary 3 Mix Gain */
73845cd29dSjmcneill AD1843_MIC_GAIN, /* Microphone Mix Gain */
74845cd29dSjmcneill AD1843_MONO_GAIN, /* Mono Mix Gain */
75845cd29dSjmcneill AD1843_DAC2_MUTE, /* DAC2 Mix Mute */
76845cd29dSjmcneill AD1843_AUX1_MUTE, /* Auxilliary 1 Mix Mute */
77845cd29dSjmcneill AD1843_AUX2_MUTE, /* Auxilliary 2 Mix Mute */
78845cd29dSjmcneill AD1843_AUX3_MUTE, /* Auxilliary 3 Mix Mute */
79845cd29dSjmcneill AD1843_MIC_MUTE, /* Microphone Mix Mute */
80845cd29dSjmcneill AD1843_MONO_MUTE, /* Mono Mix Mute */
81845cd29dSjmcneill AD1843_SUM_MUTE, /* Sum Mute */
82845cd29dSjmcneill
83845cd29dSjmcneill AD1843_OUTPUT_CLASS,
84845cd29dSjmcneill AD1843_MNO_MUTE, /* Mono Output Mute */
85845cd29dSjmcneill AD1843_HPO_MUTE /* Headphone Output Mute */
86845cd29dSjmcneill };
87845cd29dSjmcneill
88845cd29dSjmcneill /* ADC Source Select. The order matches the hardware bits. */
89845cd29dSjmcneill const char *ad1843_source[] = {
90845cd29dSjmcneill AudioNline,
91845cd29dSjmcneill AudioNmicrophone,
92845cd29dSjmcneill AudioNaux "1",
93845cd29dSjmcneill AudioNaux "2",
94845cd29dSjmcneill AudioNaux "3",
95845cd29dSjmcneill AudioNmono,
96845cd29dSjmcneill AudioNdac "1",
97845cd29dSjmcneill AudioNdac "2"
98845cd29dSjmcneill };
99845cd29dSjmcneill
100845cd29dSjmcneill /* Mix Control. The order matches the hardware register numbering. */
101845cd29dSjmcneill const char *ad1843_input[] = {
102845cd29dSjmcneill AudioNdac "2", /* AD1843_DAC2__TO_MIXER */
103845cd29dSjmcneill AudioNaux "1",
104845cd29dSjmcneill AudioNaux "2",
105845cd29dSjmcneill AudioNaux "3",
106845cd29dSjmcneill AudioNmicrophone,
107845cd29dSjmcneill AudioNmono /* AD1843_MISC_SETTINGS */
108845cd29dSjmcneill };
109845cd29dSjmcneill
110e622eac4Sisaki static const struct audio_format mavb_formats[] = {
111e622eac4Sisaki {
112e622eac4Sisaki .mode = AUMODE_PLAY,
113e622eac4Sisaki .encoding = AUDIO_ENCODING_SLINEAR_BE,
114e622eac4Sisaki .validbits = 24,
115e622eac4Sisaki .precision = 32,
116e622eac4Sisaki .channels = 2,
117e622eac4Sisaki .channel_mask = AUFMT_STEREO,
118e622eac4Sisaki .frequency_type = 0,
119e622eac4Sisaki .frequency = { 8000, 48000 },
120e622eac4Sisaki },
121de1fd2ebSjmcneill };
122e622eac4Sisaki #define MAVB_NFORMATS __arraycount(mavb_formats)
123de1fd2ebSjmcneill
124845cd29dSjmcneill struct mavb_softc {
125cbab9cadSchs device_t sc_dev;
1268a962f23Sjmcneill kmutex_t sc_lock;
1278a962f23Sjmcneill kmutex_t sc_intr_lock;
128845cd29dSjmcneill bus_space_tag_t sc_st;
129845cd29dSjmcneill bus_space_handle_t sc_sh;
130845cd29dSjmcneill bus_dma_tag_t sc_dmat;
131845cd29dSjmcneill bus_dmamap_t sc_dmamap;
132845cd29dSjmcneill
133845cd29dSjmcneill /* XXX We need access to some of the MACE ISA registers. */
134845cd29dSjmcneill bus_space_handle_t sc_isash;
135845cd29dSjmcneill
136845cd29dSjmcneill #define MAVB_ISA_RING_SIZE 0x1000
137845cd29dSjmcneill uint8_t *sc_ring;
138845cd29dSjmcneill
139845cd29dSjmcneill uint8_t *sc_start, *sc_end;
140845cd29dSjmcneill int sc_blksize;
141845cd29dSjmcneill void (*sc_intr)(void *);
142845cd29dSjmcneill void *sc_intrarg;
143845cd29dSjmcneill
144845cd29dSjmcneill void *sc_get;
145845cd29dSjmcneill int sc_count;
146845cd29dSjmcneill
147845cd29dSjmcneill u_long sc_play_rate;
148845cd29dSjmcneill u_int sc_play_format;
149845cd29dSjmcneill
150845cd29dSjmcneill struct callout sc_volume_button_ch;
151845cd29dSjmcneill };
152845cd29dSjmcneill
1531db87857Stsutsui typedef uint64_t ad1843_addr_t;
154845cd29dSjmcneill
1551db87857Stsutsui uint16_t ad1843_reg_read(struct mavb_softc *, ad1843_addr_t);
1561db87857Stsutsui uint16_t ad1843_reg_write(struct mavb_softc *, ad1843_addr_t, uint16_t);
157845cd29dSjmcneill void ad1843_dump_regs(struct mavb_softc *);
158845cd29dSjmcneill
159cbab9cadSchs int mavb_match(device_t, cfdata_t, void *);
160cbab9cadSchs void mavb_attach(device_t, device_t, void *);
161845cd29dSjmcneill
162cbab9cadSchs CFATTACH_DECL_NEW(mavb, sizeof(struct mavb_softc),
163845cd29dSjmcneill mavb_match, mavb_attach, NULL, NULL);
164845cd29dSjmcneill
165e622eac4Sisaki int mavb_query_format(void *, audio_format_query_t *);
166e622eac4Sisaki int mavb_set_format(void *, int,
167e622eac4Sisaki const audio_params_t *, const audio_params_t *,
168e622eac4Sisaki audio_filter_reg_t *, audio_filter_reg_t *);
169845cd29dSjmcneill int mavb_round_blocksize(void *hdl, int, int, const audio_params_t *);
170845cd29dSjmcneill int mavb_halt_output(void *);
171845cd29dSjmcneill int mavb_halt_input(void *);
172845cd29dSjmcneill int mavb_getdev(void *, struct audio_device *);
173845cd29dSjmcneill int mavb_set_port(void *, struct mixer_ctrl *);
174845cd29dSjmcneill int mavb_get_port(void *, struct mixer_ctrl *);
175845cd29dSjmcneill int mavb_query_devinfo(void *, struct mixer_devinfo *);
176845cd29dSjmcneill int mavb_get_props(void *);
177845cd29dSjmcneill int mavb_trigger_output(void *, void *, void *, int, void (*)(void *),
178845cd29dSjmcneill void *, const audio_params_t *);
179845cd29dSjmcneill int mavb_trigger_input(void *, void *, void *, int, void (*)(void *),
180845cd29dSjmcneill void *, const audio_params_t *);
1818a962f23Sjmcneill void mavb_get_locks(void *, kmutex_t **, kmutex_t **);
182845cd29dSjmcneill
183845cd29dSjmcneill struct audio_hw_if mavb_sa_hw_if = {
184e622eac4Sisaki .query_format = mavb_query_format,
185e622eac4Sisaki .set_format = mavb_set_format,
1866291b134Sisaki .round_blocksize = mavb_round_blocksize,
1876291b134Sisaki .halt_output = mavb_halt_output,
1886291b134Sisaki .halt_input = mavb_halt_input,
1896291b134Sisaki .getdev = mavb_getdev,
1906291b134Sisaki .set_port = mavb_set_port,
1916291b134Sisaki .get_port = mavb_get_port,
1926291b134Sisaki .query_devinfo = mavb_query_devinfo,
1936291b134Sisaki .get_props = mavb_get_props,
1946291b134Sisaki .trigger_output = mavb_trigger_output,
1956291b134Sisaki .trigger_input = mavb_trigger_input,
1966291b134Sisaki .get_locks = mavb_get_locks,
197845cd29dSjmcneill };
198845cd29dSjmcneill
199845cd29dSjmcneill struct audio_device mavb_device = {
200845cd29dSjmcneill "A3",
201845cd29dSjmcneill "",
202845cd29dSjmcneill "mavb"
203845cd29dSjmcneill };
204845cd29dSjmcneill
205e622eac4Sisaki static void
mavb_internal_to_slinear24_32(audio_filter_arg_t * arg)206e622eac4Sisaki mavb_internal_to_slinear24_32(audio_filter_arg_t *arg)
207845cd29dSjmcneill {
208e622eac4Sisaki const aint_t *src;
209e622eac4Sisaki uint32_t *dst;
210e622eac4Sisaki u_int sample_count;
211e622eac4Sisaki u_int i;
2121db87857Stsutsui
213e622eac4Sisaki src = arg->src;
214e622eac4Sisaki dst = arg->dst;
215e622eac4Sisaki sample_count = arg->count * arg->srcfmt->channels;
216e622eac4Sisaki for (i = 0; i < sample_count; i++) {
217e622eac4Sisaki *dst++ = (*src++) << 8;
218845cd29dSjmcneill }
219845cd29dSjmcneill }
220845cd29dSjmcneill
221845cd29dSjmcneill int
mavb_query_format(void * hdl,audio_format_query_t * afp)222e622eac4Sisaki mavb_query_format(void *hdl, audio_format_query_t *afp)
223845cd29dSjmcneill {
224845cd29dSjmcneill
225e622eac4Sisaki return audio_query_format(mavb_formats, MAVB_NFORMATS, afp);
226845cd29dSjmcneill }
227845cd29dSjmcneill
228845cd29dSjmcneill static int
mavb_set_play_rate(struct mavb_softc * sc,u_long sample_rate)229845cd29dSjmcneill mavb_set_play_rate(struct mavb_softc *sc, u_long sample_rate)
230845cd29dSjmcneill {
2311db87857Stsutsui
232e622eac4Sisaki KASSERT((4000 <= sample_rate && sample_rate <= 48000));
233845cd29dSjmcneill
234845cd29dSjmcneill if (sc->sc_play_rate != sample_rate) {
235845cd29dSjmcneill ad1843_reg_write(sc, AD1843_CLOCK2_SAMPLE_RATE, sample_rate);
236845cd29dSjmcneill sc->sc_play_rate = sample_rate;
237845cd29dSjmcneill }
2381db87857Stsutsui return 0;
239845cd29dSjmcneill }
240845cd29dSjmcneill
241845cd29dSjmcneill static int
mavb_set_play_format(struct mavb_softc * sc,u_int encoding)242845cd29dSjmcneill mavb_set_play_format(struct mavb_softc *sc, u_int encoding)
243845cd29dSjmcneill {
2441db87857Stsutsui uint16_t value;
245845cd29dSjmcneill u_int format;
246845cd29dSjmcneill
247845cd29dSjmcneill switch(encoding) {
248845cd29dSjmcneill case AUDIO_ENCODING_SLINEAR_BE:
249845cd29dSjmcneill format = AD1843_PCM16;
250845cd29dSjmcneill break;
251845cd29dSjmcneill default:
2521db87857Stsutsui return EINVAL;
253845cd29dSjmcneill }
254845cd29dSjmcneill
255845cd29dSjmcneill if (sc->sc_play_format != format) {
256845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_SERIAL_INTERFACE);
257845cd29dSjmcneill value &= ~AD1843_DA1F_MASK;
258845cd29dSjmcneill value |= (format << AD1843_DA1F_SHIFT);
259845cd29dSjmcneill ad1843_reg_write(sc, AD1843_SERIAL_INTERFACE, value);
260845cd29dSjmcneill sc->sc_play_format = format;
261845cd29dSjmcneill }
2621db87857Stsutsui return 0;
263845cd29dSjmcneill }
264845cd29dSjmcneill
265845cd29dSjmcneill int
mavb_set_format(void * hdl,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)266e622eac4Sisaki mavb_set_format(void *hdl, int setmode,
267e622eac4Sisaki const audio_params_t *play, const audio_params_t *rec,
268e622eac4Sisaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
269845cd29dSjmcneill {
270845cd29dSjmcneill struct mavb_softc *sc = (struct mavb_softc *)hdl;
271845cd29dSjmcneill int error;
272845cd29dSjmcneill
273e622eac4Sisaki DPRINTF(1, ("%s: %s: sample=%u precision=%d channels=%d\n",
274e622eac4Sisaki device_xname(sc->sc_dev), __func__,
275e622eac4Sisaki play->sample_rate, play->precision, play->channels));
276845cd29dSjmcneill
277845cd29dSjmcneill if (setmode & AUMODE_PLAY) {
278e622eac4Sisaki pfil->codec = mavb_internal_to_slinear24_32;
279845cd29dSjmcneill
280e622eac4Sisaki error = mavb_set_play_rate(sc, play->sample_rate);
281845cd29dSjmcneill if (error)
2821db87857Stsutsui return error;
283845cd29dSjmcneill
284e622eac4Sisaki error = mavb_set_play_format(sc, play->encoding);
285845cd29dSjmcneill if (error)
2861db87857Stsutsui return error;
287845cd29dSjmcneill }
288845cd29dSjmcneill
289845cd29dSjmcneill #if 0
290845cd29dSjmcneill if (setmode & AUMODE_RECORD) {
291845cd29dSjmcneill }
292845cd29dSjmcneill #endif
293845cd29dSjmcneill
2941db87857Stsutsui return 0;
295845cd29dSjmcneill }
296845cd29dSjmcneill
297845cd29dSjmcneill int
mavb_round_blocksize(void * hdl,int bs,int mode,const audio_params_t * p)298845cd29dSjmcneill mavb_round_blocksize(void *hdl, int bs, int mode, const audio_params_t *p)
299845cd29dSjmcneill {
3001db87857Stsutsui
301845cd29dSjmcneill /* Block size should be a multiple of 32. */
302845cd29dSjmcneill return (bs + 0x1f) & ~0x1f;
303845cd29dSjmcneill }
304845cd29dSjmcneill
305845cd29dSjmcneill int
mavb_halt_output(void * hdl)306845cd29dSjmcneill mavb_halt_output(void *hdl)
307845cd29dSjmcneill {
308845cd29dSjmcneill struct mavb_softc *sc = (struct mavb_softc *)hdl;
309845cd29dSjmcneill
310cbab9cadSchs DPRINTF(1, ("%s: mavb_halt_output called\n", device_xname(sc->sc_dev)));
311845cd29dSjmcneill
312845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CHANNEL2_CONTROL, 0);
3131db87857Stsutsui return 0;
314845cd29dSjmcneill }
315845cd29dSjmcneill
316845cd29dSjmcneill int
mavb_halt_input(void * hdl)317845cd29dSjmcneill mavb_halt_input(void *hdl)
318845cd29dSjmcneill {
3191db87857Stsutsui
3201db87857Stsutsui return 0;
321845cd29dSjmcneill }
322845cd29dSjmcneill
323845cd29dSjmcneill int
mavb_getdev(void * hdl,struct audio_device * ret)324845cd29dSjmcneill mavb_getdev(void *hdl, struct audio_device *ret)
325845cd29dSjmcneill {
3261db87857Stsutsui
327845cd29dSjmcneill *ret = mavb_device;
3281db87857Stsutsui return 0;
329845cd29dSjmcneill }
330845cd29dSjmcneill
331845cd29dSjmcneill int
mavb_set_port(void * hdl,struct mixer_ctrl * mc)332845cd29dSjmcneill mavb_set_port(void *hdl, struct mixer_ctrl *mc)
333845cd29dSjmcneill {
334845cd29dSjmcneill struct mavb_softc *sc = (struct mavb_softc *)hdl;
335845cd29dSjmcneill u_char left, right;
336845cd29dSjmcneill ad1843_addr_t reg;
3371db87857Stsutsui uint16_t value;
338845cd29dSjmcneill
339cbab9cadSchs DPRINTF(1, ("%s: mavb_set_port: dev=%d\n", device_xname(sc->sc_dev),
340845cd29dSjmcneill mc->dev));
341845cd29dSjmcneill
342845cd29dSjmcneill switch (mc->dev) {
343845cd29dSjmcneill case AD1843_ADC_SOURCE:
344845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_ADC_SOURCE_GAIN);
345845cd29dSjmcneill value &= ~(AD1843_LSS_MASK | AD1843_RSS_MASK);
346845cd29dSjmcneill value |= ((mc->un.ord << AD1843_LSS_SHIFT) & AD1843_LSS_MASK);
347845cd29dSjmcneill value |= ((mc->un.ord << AD1843_RSS_SHIFT) & AD1843_RSS_MASK);
348845cd29dSjmcneill ad1843_reg_write(sc, AD1843_ADC_SOURCE_GAIN, value);
349845cd29dSjmcneill break;
350845cd29dSjmcneill case AD1843_ADC_GAIN:
351845cd29dSjmcneill left = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
352845cd29dSjmcneill right = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
353845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_ADC_SOURCE_GAIN);
354845cd29dSjmcneill value &= ~(AD1843_LIG_MASK | AD1843_RIG_MASK);
355845cd29dSjmcneill value |= ((left >> 4) << AD1843_LIG_SHIFT);
356845cd29dSjmcneill value |= ((right >> 4) << AD1843_RIG_SHIFT);
357845cd29dSjmcneill ad1843_reg_write(sc, AD1843_ADC_SOURCE_GAIN, value);
358845cd29dSjmcneill break;
359845cd29dSjmcneill
360845cd29dSjmcneill case AD1843_DAC1_GAIN:
361845cd29dSjmcneill left = AUDIO_MAX_GAIN -
362845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
363845cd29dSjmcneill right = AUDIO_MAX_GAIN -
364845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
365845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
366845cd29dSjmcneill value &= ~(AD1843_LDA1G_MASK | AD1843_RDA1G_MASK);
367845cd29dSjmcneill value |= ((left >> 2) << AD1843_LDA1G_SHIFT);
368845cd29dSjmcneill value |= ((right >> 2) << AD1843_RDA1G_SHIFT);
369845cd29dSjmcneill ad1843_reg_write(sc, AD1843_DAC1_ANALOG_GAIN, value);
370845cd29dSjmcneill break;
371845cd29dSjmcneill case AD1843_DAC1_MUTE:
372845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
373845cd29dSjmcneill if (mc->un.ord == 0)
374845cd29dSjmcneill value &= ~(AD1843_LDA1GM | AD1843_RDA1GM);
375845cd29dSjmcneill else
376845cd29dSjmcneill value |= (AD1843_LDA1GM | AD1843_RDA1GM);
377845cd29dSjmcneill ad1843_reg_write(sc, AD1843_DAC1_ANALOG_GAIN, value);
378845cd29dSjmcneill break;
379845cd29dSjmcneill
380845cd29dSjmcneill case AD1843_DAC2_GAIN:
381845cd29dSjmcneill case AD1843_AUX1_GAIN:
382845cd29dSjmcneill case AD1843_AUX2_GAIN:
383845cd29dSjmcneill case AD1843_AUX3_GAIN:
384845cd29dSjmcneill case AD1843_MIC_GAIN:
385845cd29dSjmcneill left = AUDIO_MAX_GAIN -
386845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
387845cd29dSjmcneill right = AUDIO_MAX_GAIN -
388845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
389845cd29dSjmcneill reg = AD1843_DAC2_TO_MIXER + mc->dev - AD1843_DAC2_GAIN;
390845cd29dSjmcneill value = ad1843_reg_read(sc, reg);
391845cd29dSjmcneill value &= ~(AD1843_LD2M_MASK | AD1843_RD2M_MASK);
392845cd29dSjmcneill value |= ((left >> 3) << AD1843_LD2M_SHIFT);
393845cd29dSjmcneill value |= ((right >> 3) << AD1843_RD2M_SHIFT);
394845cd29dSjmcneill ad1843_reg_write(sc, reg, value);
395845cd29dSjmcneill break;
396845cd29dSjmcneill case AD1843_MONO_GAIN:
397845cd29dSjmcneill left = AUDIO_MAX_GAIN -
398845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
399845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
400845cd29dSjmcneill value &= ~AD1843_MNM_MASK;
401845cd29dSjmcneill value |= ((left >> 3) << AD1843_MNM_SHIFT);
402845cd29dSjmcneill ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
403845cd29dSjmcneill break;
404845cd29dSjmcneill case AD1843_DAC2_MUTE:
405845cd29dSjmcneill case AD1843_AUX1_MUTE:
406845cd29dSjmcneill case AD1843_AUX2_MUTE:
407845cd29dSjmcneill case AD1843_AUX3_MUTE:
408845cd29dSjmcneill case AD1843_MIC_MUTE:
409845cd29dSjmcneill case AD1843_MONO_MUTE: /* matches left channel */
410845cd29dSjmcneill reg = AD1843_DAC2_TO_MIXER + mc->dev - AD1843_DAC2_MUTE;
411845cd29dSjmcneill value = ad1843_reg_read(sc, reg);
412845cd29dSjmcneill if (mc->un.ord == 0)
413845cd29dSjmcneill value &= ~(AD1843_LD2MM | AD1843_RD2MM);
414845cd29dSjmcneill else
415845cd29dSjmcneill value |= (AD1843_LD2MM | AD1843_RD2MM);
416845cd29dSjmcneill ad1843_reg_write(sc, reg, value);
417845cd29dSjmcneill break;
418845cd29dSjmcneill
419845cd29dSjmcneill case AD1843_SUM_MUTE:
420845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
421845cd29dSjmcneill if (mc->un.ord == 0)
422845cd29dSjmcneill value &= ~AD1843_SUMM;
423845cd29dSjmcneill else
424845cd29dSjmcneill value |= AD1843_SUMM;
425845cd29dSjmcneill ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
426845cd29dSjmcneill break;
427845cd29dSjmcneill
428845cd29dSjmcneill case AD1843_MNO_MUTE:
429845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
430845cd29dSjmcneill if (mc->un.ord == 0)
431845cd29dSjmcneill value &= ~AD1843_MNOM;
432845cd29dSjmcneill else
433845cd29dSjmcneill value |= AD1843_MNOM;
434845cd29dSjmcneill ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
435845cd29dSjmcneill break;
436845cd29dSjmcneill
437845cd29dSjmcneill case AD1843_HPO_MUTE:
438845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
439845cd29dSjmcneill if (mc->un.ord == 0)
440845cd29dSjmcneill value &= ~AD1843_HPOM;
441845cd29dSjmcneill else
442845cd29dSjmcneill value |= AD1843_HPOM;
443845cd29dSjmcneill ad1843_reg_write(sc, AD1843_MISC_SETTINGS, value);
444845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
445845cd29dSjmcneill break;
446845cd29dSjmcneill
447845cd29dSjmcneill default:
4481db87857Stsutsui return EINVAL;
449845cd29dSjmcneill }
450845cd29dSjmcneill
4511db87857Stsutsui return 0;
452845cd29dSjmcneill }
453845cd29dSjmcneill
454845cd29dSjmcneill int
mavb_get_port(void * hdl,struct mixer_ctrl * mc)455845cd29dSjmcneill mavb_get_port(void *hdl, struct mixer_ctrl *mc)
456845cd29dSjmcneill {
457845cd29dSjmcneill struct mavb_softc *sc = (struct mavb_softc *)hdl;
458845cd29dSjmcneill u_char left, right;
459845cd29dSjmcneill ad1843_addr_t reg;
4601db87857Stsutsui uint16_t value;
461845cd29dSjmcneill
462cbab9cadSchs DPRINTF(1, ("%s: mavb_get_port: dev=%d\n", device_xname(sc->sc_dev),
463845cd29dSjmcneill mc->dev));
464845cd29dSjmcneill
465845cd29dSjmcneill switch (mc->dev) {
466845cd29dSjmcneill case AD1843_ADC_SOURCE:
467845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_ADC_SOURCE_GAIN);
468845cd29dSjmcneill mc->un.ord = (value & AD1843_LSS_MASK) >> AD1843_LSS_SHIFT;
469845cd29dSjmcneill break;
470845cd29dSjmcneill case AD1843_ADC_GAIN:
471845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_ADC_SOURCE_GAIN);
472845cd29dSjmcneill left = (value & AD1843_LIG_MASK) >> AD1843_LIG_SHIFT;
473845cd29dSjmcneill right = (value & AD1843_RIG_MASK) >> AD1843_RIG_SHIFT;
474845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
475845cd29dSjmcneill (left << 4) | left;
476845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
477845cd29dSjmcneill (right << 2) | right;
478845cd29dSjmcneill break;
479845cd29dSjmcneill
480845cd29dSjmcneill case AD1843_DAC1_GAIN:
481845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
482845cd29dSjmcneill left = (value & AD1843_LDA1G_MASK) >> AD1843_LDA1G_SHIFT;
483845cd29dSjmcneill right = (value & AD1843_RDA1G_MASK) >> AD1843_RDA1G_SHIFT;
484845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
485845cd29dSjmcneill AUDIO_MAX_GAIN - (left << 2);
486845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
487845cd29dSjmcneill AUDIO_MAX_GAIN - (right << 2);
488845cd29dSjmcneill break;
489845cd29dSjmcneill case AD1843_DAC1_MUTE:
490845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
491845cd29dSjmcneill mc->un.ord = (value & AD1843_LDA1GM) ? 1 : 0;
492845cd29dSjmcneill break;
493845cd29dSjmcneill
494845cd29dSjmcneill case AD1843_DAC2_GAIN:
495845cd29dSjmcneill case AD1843_AUX1_GAIN:
496845cd29dSjmcneill case AD1843_AUX2_GAIN:
497845cd29dSjmcneill case AD1843_AUX3_GAIN:
498845cd29dSjmcneill case AD1843_MIC_GAIN:
499845cd29dSjmcneill reg = AD1843_DAC2_TO_MIXER + mc->dev - AD1843_DAC2_GAIN;
500845cd29dSjmcneill value = ad1843_reg_read(sc, reg);
501845cd29dSjmcneill left = (value & AD1843_LD2M_MASK) >> AD1843_LD2M_SHIFT;
502845cd29dSjmcneill right = (value & AD1843_RD2M_MASK) >> AD1843_RD2M_SHIFT;
503845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
504845cd29dSjmcneill AUDIO_MAX_GAIN - (left << 3);
505845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
506845cd29dSjmcneill AUDIO_MAX_GAIN - (right << 3);
507845cd29dSjmcneill break;
508845cd29dSjmcneill case AD1843_MONO_GAIN:
509845cd29dSjmcneill if (mc->un.value.num_channels != 1)
5101db87857Stsutsui return EINVAL;
511845cd29dSjmcneill
512845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
513845cd29dSjmcneill left = (value & AD1843_MNM_MASK) >> AD1843_MNM_SHIFT;
514845cd29dSjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
515845cd29dSjmcneill AUDIO_MAX_GAIN - (left << 3);
516845cd29dSjmcneill break;
517845cd29dSjmcneill case AD1843_DAC2_MUTE:
518845cd29dSjmcneill case AD1843_AUX1_MUTE:
519845cd29dSjmcneill case AD1843_AUX2_MUTE:
520845cd29dSjmcneill case AD1843_AUX3_MUTE:
521845cd29dSjmcneill case AD1843_MIC_MUTE:
522845cd29dSjmcneill case AD1843_MONO_MUTE: /* matches left channel */
523845cd29dSjmcneill reg = AD1843_DAC2_TO_MIXER + mc->dev - AD1843_DAC2_MUTE;
524845cd29dSjmcneill value = ad1843_reg_read(sc, reg);
525845cd29dSjmcneill mc->un.ord = (value & AD1843_LD2MM) ? 1 : 0;
526845cd29dSjmcneill break;
527845cd29dSjmcneill
528845cd29dSjmcneill case AD1843_SUM_MUTE:
529845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
530845cd29dSjmcneill mc->un.ord = (value & AD1843_SUMM) ? 1 : 0;
531845cd29dSjmcneill break;
532845cd29dSjmcneill
533845cd29dSjmcneill case AD1843_MNO_MUTE:
534845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
535845cd29dSjmcneill mc->un.ord = (value & AD1843_MNOM) ? 1 : 0;
536845cd29dSjmcneill break;
537845cd29dSjmcneill
538845cd29dSjmcneill case AD1843_HPO_MUTE:
539845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
540845cd29dSjmcneill mc->un.ord = (value & AD1843_HPOM) ? 1 : 0;
541845cd29dSjmcneill break;
542845cd29dSjmcneill
543845cd29dSjmcneill default:
5441db87857Stsutsui return EINVAL;
545845cd29dSjmcneill }
546845cd29dSjmcneill
5471db87857Stsutsui return 0;
548845cd29dSjmcneill }
549845cd29dSjmcneill
550845cd29dSjmcneill int
mavb_query_devinfo(void * hdl,struct mixer_devinfo * di)551845cd29dSjmcneill mavb_query_devinfo(void *hdl, struct mixer_devinfo *di)
552845cd29dSjmcneill {
553845cd29dSjmcneill int i;
554845cd29dSjmcneill
555845cd29dSjmcneill di->prev = di->next = AUDIO_MIXER_LAST;
556845cd29dSjmcneill
557845cd29dSjmcneill switch (di->index) {
558845cd29dSjmcneill case AD1843_RECORD_CLASS:
559845cd29dSjmcneill di->type = AUDIO_MIXER_CLASS;
560845cd29dSjmcneill di->mixer_class = AD1843_RECORD_CLASS;
561845cd29dSjmcneill strlcpy(di->label.name, AudioCrecord, sizeof di->label.name);
562845cd29dSjmcneill break;
563845cd29dSjmcneill
564845cd29dSjmcneill case AD1843_ADC_SOURCE:
565845cd29dSjmcneill di->type = AUDIO_MIXER_ENUM;
566845cd29dSjmcneill di->mixer_class = AD1843_RECORD_CLASS;
567845cd29dSjmcneill di->next = AD1843_ADC_GAIN;
568845cd29dSjmcneill strlcpy(di->label.name, AudioNsource, sizeof di->label.name);
569845cd29dSjmcneill di->un.e.num_mem =
570845cd29dSjmcneill sizeof ad1843_source / sizeof ad1843_source[1];
571845cd29dSjmcneill for (i = 0; i < di->un.e.num_mem; i++) {
572845cd29dSjmcneill strlcpy(di->un.e.member[i].label.name,
573845cd29dSjmcneill ad1843_source[i],
574845cd29dSjmcneill sizeof di->un.e.member[0].label.name);
575845cd29dSjmcneill di->un.e.member[i].ord = i;
576845cd29dSjmcneill }
577845cd29dSjmcneill break;
578845cd29dSjmcneill case AD1843_ADC_GAIN:
579845cd29dSjmcneill di->type = AUDIO_MIXER_VALUE;
580845cd29dSjmcneill di->mixer_class = AD1843_RECORD_CLASS;
581845cd29dSjmcneill di->prev = AD1843_ADC_SOURCE;
582845cd29dSjmcneill strlcpy(di->label.name, AudioNvolume, sizeof di->label.name);
583845cd29dSjmcneill di->un.v.num_channels = 2;
584845cd29dSjmcneill strlcpy(di->un.v.units.name, AudioNvolume,
585845cd29dSjmcneill sizeof di->un.v.units.name);
586845cd29dSjmcneill break;
587845cd29dSjmcneill
588845cd29dSjmcneill case AD1843_INPUT_CLASS:
589845cd29dSjmcneill di->type = AUDIO_MIXER_CLASS;
590845cd29dSjmcneill di->mixer_class = AD1843_INPUT_CLASS;
591845cd29dSjmcneill strlcpy(di->label.name, AudioCinputs, sizeof di->label.name);
592845cd29dSjmcneill break;
593845cd29dSjmcneill
594845cd29dSjmcneill case AD1843_DAC1_GAIN:
595845cd29dSjmcneill di->type = AUDIO_MIXER_VALUE;
596a3fb1dc4Smacallan di->mixer_class = AD1843_OUTPUT_CLASS;
597845cd29dSjmcneill di->next = AD1843_DAC1_MUTE;
598a3fb1dc4Smacallan strlcpy(di->label.name, AudioNmaster, sizeof di->label.name);
599845cd29dSjmcneill di->un.v.num_channels = 2;
600845cd29dSjmcneill strlcpy(di->un.v.units.name, AudioNvolume,
601845cd29dSjmcneill sizeof di->un.v.units.name);
602845cd29dSjmcneill break;
603845cd29dSjmcneill case AD1843_DAC1_MUTE:
604845cd29dSjmcneill di->type = AUDIO_MIXER_ENUM;
605a3fb1dc4Smacallan di->mixer_class = AD1843_OUTPUT_CLASS;
606845cd29dSjmcneill di->prev = AD1843_DAC1_GAIN;
607845cd29dSjmcneill strlcpy(di->label.name, AudioNmute, sizeof di->label.name);
608845cd29dSjmcneill di->un.e.num_mem = 2;
609845cd29dSjmcneill strlcpy(di->un.e.member[0].label.name, AudioNoff,
610845cd29dSjmcneill sizeof di->un.e.member[0].label.name);
611845cd29dSjmcneill di->un.e.member[0].ord = 0;
612845cd29dSjmcneill strlcpy(di->un.e.member[1].label.name, AudioNon,
613845cd29dSjmcneill sizeof di->un.e.member[1].label.name);
614845cd29dSjmcneill di->un.e.member[1].ord = 1;
615845cd29dSjmcneill break;
616845cd29dSjmcneill
617845cd29dSjmcneill case AD1843_DAC2_GAIN:
618845cd29dSjmcneill case AD1843_AUX1_GAIN:
619845cd29dSjmcneill case AD1843_AUX2_GAIN:
620845cd29dSjmcneill case AD1843_AUX3_GAIN:
621845cd29dSjmcneill case AD1843_MIC_GAIN:
622845cd29dSjmcneill case AD1843_MONO_GAIN:
623845cd29dSjmcneill di->type = AUDIO_MIXER_VALUE;
624845cd29dSjmcneill di->mixer_class = AD1843_INPUT_CLASS;
625845cd29dSjmcneill di->next = di->index + AD1843_DAC2_MUTE - AD1843_DAC2_GAIN;
626845cd29dSjmcneill strlcpy(di->label.name,
627845cd29dSjmcneill ad1843_input[di->index - AD1843_DAC2_GAIN],
628845cd29dSjmcneill sizeof di->label.name);
629845cd29dSjmcneill if (di->index == AD1843_MONO_GAIN)
630845cd29dSjmcneill di->un.v.num_channels = 1;
631845cd29dSjmcneill else
632845cd29dSjmcneill di->un.v.num_channels = 2;
633845cd29dSjmcneill strlcpy(di->un.v.units.name, AudioNvolume,
634845cd29dSjmcneill sizeof di->un.v.units.name);
635845cd29dSjmcneill break;
636845cd29dSjmcneill case AD1843_DAC2_MUTE:
637845cd29dSjmcneill case AD1843_AUX1_MUTE:
638845cd29dSjmcneill case AD1843_AUX2_MUTE:
639845cd29dSjmcneill case AD1843_AUX3_MUTE:
640845cd29dSjmcneill case AD1843_MIC_MUTE:
641845cd29dSjmcneill case AD1843_MONO_MUTE:
642845cd29dSjmcneill di->type = AUDIO_MIXER_ENUM;
643845cd29dSjmcneill di->mixer_class = AD1843_INPUT_CLASS;
644845cd29dSjmcneill di->prev = di->index + AD1843_DAC2_GAIN - AD1843_DAC2_MUTE;
645845cd29dSjmcneill strlcpy(di->label.name, AudioNmute, sizeof di->label.name);
646845cd29dSjmcneill di->un.e.num_mem = 2;
647845cd29dSjmcneill strlcpy(di->un.e.member[0].label.name, AudioNoff,
648845cd29dSjmcneill sizeof di->un.e.member[0].label.name);
649845cd29dSjmcneill di->un.e.member[0].ord = 0;
650845cd29dSjmcneill strlcpy(di->un.e.member[1].label.name, AudioNon,
651845cd29dSjmcneill sizeof di->un.e.member[1].label.name);
652845cd29dSjmcneill di->un.e.member[1].ord = 1;
653845cd29dSjmcneill break;
654845cd29dSjmcneill
655845cd29dSjmcneill case AD1843_SUM_MUTE:
656845cd29dSjmcneill di->type = AUDIO_MIXER_ENUM;
657845cd29dSjmcneill di->mixer_class = AD1843_INPUT_CLASS;
658845cd29dSjmcneill strlcpy(di->label.name, "sum." AudioNmute,
659845cd29dSjmcneill sizeof di->label.name);
660845cd29dSjmcneill di->un.e.num_mem = 2;
661845cd29dSjmcneill strlcpy(di->un.e.member[0].label.name, AudioNoff,
662845cd29dSjmcneill sizeof di->un.e.member[0].label.name);
663845cd29dSjmcneill di->un.e.member[0].ord = 0;
664845cd29dSjmcneill strlcpy(di->un.e.member[1].label.name, AudioNon,
665845cd29dSjmcneill sizeof di->un.e.member[1].label.name);
666845cd29dSjmcneill di->un.e.member[1].ord = 1;
667845cd29dSjmcneill break;
668845cd29dSjmcneill
669845cd29dSjmcneill case AD1843_OUTPUT_CLASS:
670845cd29dSjmcneill di->type = AUDIO_MIXER_CLASS;
671845cd29dSjmcneill di->mixer_class = AD1843_OUTPUT_CLASS;
672845cd29dSjmcneill strlcpy(di->label.name, AudioCoutputs, sizeof di->label.name);
673845cd29dSjmcneill break;
674845cd29dSjmcneill
675845cd29dSjmcneill case AD1843_MNO_MUTE:
676845cd29dSjmcneill di->type = AUDIO_MIXER_ENUM;
677845cd29dSjmcneill di->mixer_class = AD1843_OUTPUT_CLASS;
678845cd29dSjmcneill strlcpy(di->label.name, AudioNmono "." AudioNmute,
679845cd29dSjmcneill sizeof di->label.name);
680845cd29dSjmcneill di->un.e.num_mem = 2;
681845cd29dSjmcneill strlcpy(di->un.e.member[0].label.name, AudioNoff,
682845cd29dSjmcneill sizeof di->un.e.member[0].label.name);
683845cd29dSjmcneill di->un.e.member[0].ord = 0;
684845cd29dSjmcneill strlcpy(di->un.e.member[1].label.name, AudioNon,
685845cd29dSjmcneill sizeof di->un.e.member[1].label.name);
686845cd29dSjmcneill di->un.e.member[1].ord = 1;
687845cd29dSjmcneill break;
688845cd29dSjmcneill
689845cd29dSjmcneill case AD1843_HPO_MUTE:
690845cd29dSjmcneill di->type = AUDIO_MIXER_ENUM;
691845cd29dSjmcneill di->mixer_class = AD1843_OUTPUT_CLASS;
692845cd29dSjmcneill strlcpy(di->label.name, AudioNheadphone "." AudioNmute,
693845cd29dSjmcneill sizeof di->label.name);
694845cd29dSjmcneill di->un.e.num_mem = 2;
695845cd29dSjmcneill strlcpy(di->un.e.member[0].label.name, AudioNoff,
696845cd29dSjmcneill sizeof di->un.e.member[0].label.name);
697845cd29dSjmcneill di->un.e.member[0].ord = 0;
698845cd29dSjmcneill strlcpy(di->un.e.member[1].label.name, AudioNon,
699845cd29dSjmcneill sizeof di->un.e.member[1].label.name);
700845cd29dSjmcneill di->un.e.member[1].ord = 1;
701845cd29dSjmcneill break;
702845cd29dSjmcneill
703845cd29dSjmcneill default:
7041db87857Stsutsui return EINVAL;
705845cd29dSjmcneill }
706845cd29dSjmcneill
7071db87857Stsutsui return 0;
708845cd29dSjmcneill }
709845cd29dSjmcneill
710845cd29dSjmcneill int
mavb_get_props(void * hdl)711845cd29dSjmcneill mavb_get_props(void *hdl)
712845cd29dSjmcneill {
7131db87857Stsutsui
714*cfc80c6fSisaki return AUDIO_PROP_PLAYBACK;
715845cd29dSjmcneill }
716845cd29dSjmcneill
717845cd29dSjmcneill static void
mavb_dma_output(struct mavb_softc * sc)718845cd29dSjmcneill mavb_dma_output(struct mavb_softc *sc)
719845cd29dSjmcneill {
720845cd29dSjmcneill bus_space_tag_t st = sc->sc_st;
721845cd29dSjmcneill bus_space_handle_t sh = sc->sc_sh;
7221db87857Stsutsui uint64_t write_ptr;
7231db87857Stsutsui uint64_t depth;
724845cd29dSjmcneill uint8_t *src, *dst;
725845cd29dSjmcneill int count;
726845cd29dSjmcneill
7278a962f23Sjmcneill KASSERT(mutex_owned(&sc->sc_intr_lock));
7288a962f23Sjmcneill
729845cd29dSjmcneill write_ptr = bus_space_read_8(st, sh, MAVB_CHANNEL2_WRITE_PTR);
730845cd29dSjmcneill depth = bus_space_read_8(st, sh, MAVB_CHANNEL2_DEPTH);
731845cd29dSjmcneill
732845cd29dSjmcneill dst = sc->sc_ring + write_ptr;
733845cd29dSjmcneill src = sc->sc_get;
734845cd29dSjmcneill
735845cd29dSjmcneill count = (MAVB_ISA_RING_SIZE - depth - 32);
736845cd29dSjmcneill while (--count >= 0) {
737845cd29dSjmcneill *dst++ = *src++;
738845cd29dSjmcneill if (dst >= sc->sc_ring + MAVB_ISA_RING_SIZE)
739845cd29dSjmcneill dst = sc->sc_ring;
740845cd29dSjmcneill if (src >= sc->sc_end)
741845cd29dSjmcneill src = sc->sc_start;
742845cd29dSjmcneill if (++sc->sc_count >= sc->sc_blksize) {
743845cd29dSjmcneill if (sc->sc_intr)
744845cd29dSjmcneill sc->sc_intr(sc->sc_intrarg);
745845cd29dSjmcneill sc->sc_count = 0;
746845cd29dSjmcneill }
747845cd29dSjmcneill }
748845cd29dSjmcneill
749845cd29dSjmcneill write_ptr = dst - sc->sc_ring;
750845cd29dSjmcneill bus_space_write_8(st, sh, MAVB_CHANNEL2_WRITE_PTR, write_ptr);
751845cd29dSjmcneill sc->sc_get = src;
752845cd29dSjmcneill }
753845cd29dSjmcneill
754845cd29dSjmcneill int
mavb_trigger_output(void * hdl,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * param)755845cd29dSjmcneill mavb_trigger_output(void *hdl, void *start, void *end, int blksize,
756845cd29dSjmcneill void (*intr)(void *), void *intrarg,
757845cd29dSjmcneill const audio_params_t *param)
758845cd29dSjmcneill {
759845cd29dSjmcneill struct mavb_softc *sc = (struct mavb_softc *)hdl;
760845cd29dSjmcneill
761845cd29dSjmcneill DPRINTF(1, ("%s: mavb_trigger_output: start=%p end=%p "
762cbab9cadSchs "blksize=%d intr=%p(%p)\n", device_xname(sc->sc_dev),
763845cd29dSjmcneill start, end, blksize, intr, intrarg));
764845cd29dSjmcneill
765845cd29dSjmcneill sc->sc_blksize = blksize;
766845cd29dSjmcneill sc->sc_intr = intr;
767845cd29dSjmcneill sc->sc_intrarg = intrarg;
768845cd29dSjmcneill
769845cd29dSjmcneill sc->sc_start = sc->sc_get = start;
770845cd29dSjmcneill sc->sc_end = end;
771845cd29dSjmcneill
772845cd29dSjmcneill sc->sc_count = 0;
773845cd29dSjmcneill
774845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CHANNEL2_CONTROL,
775845cd29dSjmcneill MAVB_CHANNEL_RESET);
776845cd29dSjmcneill delay(1000);
777845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CHANNEL2_CONTROL, 0);
778845cd29dSjmcneill
779845cd29dSjmcneill mavb_dma_output(sc);
780845cd29dSjmcneill
781845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CHANNEL2_CONTROL,
782845cd29dSjmcneill MAVB_CHANNEL_DMA_ENABLE | MAVB_CHANNEL_INT_50);
7838a962f23Sjmcneill
7841db87857Stsutsui return 0;
785845cd29dSjmcneill }
786845cd29dSjmcneill
787845cd29dSjmcneill int
mavb_trigger_input(void * hdl,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * param)788845cd29dSjmcneill mavb_trigger_input(void *hdl, void *start, void *end, int blksize,
789845cd29dSjmcneill void (*intr)(void *), void *intrarg,
790845cd29dSjmcneill const audio_params_t *param)
791845cd29dSjmcneill {
7921db87857Stsutsui
7931db87857Stsutsui return 0;
794845cd29dSjmcneill }
795845cd29dSjmcneill
7968a962f23Sjmcneill void
mavb_get_locks(void * hdl,kmutex_t ** intr,kmutex_t ** thread)7978a962f23Sjmcneill mavb_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread)
7988a962f23Sjmcneill {
7998a962f23Sjmcneill struct mavb_softc *sc = (struct mavb_softc *)hdl;
8008a962f23Sjmcneill
8018a962f23Sjmcneill *intr = &sc->sc_intr_lock;
8028a962f23Sjmcneill *thread = &sc->sc_lock;
8038a962f23Sjmcneill }
8048a962f23Sjmcneill
805845cd29dSjmcneill static void
mavb_button_repeat(void * hdl)806845cd29dSjmcneill mavb_button_repeat(void *hdl)
807845cd29dSjmcneill {
808845cd29dSjmcneill struct mavb_softc *sc = (struct mavb_softc *)hdl;
8091db87857Stsutsui uint64_t intmask, control;
8101db87857Stsutsui uint16_t value, left, right;
811845cd29dSjmcneill
812cbab9cadSchs DPRINTF(1, ("%s: mavb_repeat called\n", device_xname(sc->sc_dev)));
813845cd29dSjmcneill
814845cd29dSjmcneill #define MAVB_CONTROL_VOLUME_BUTTONS \
815845cd29dSjmcneill (MAVB_CONTROL_VOLUME_BUTTON_UP | MAVB_CONTROL_VOLUME_BUTTON_DOWN)
816845cd29dSjmcneill
817845cd29dSjmcneill control = bus_space_read_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL);
818845cd29dSjmcneill if (control & MAVB_CONTROL_VOLUME_BUTTONS) {
819845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
820845cd29dSjmcneill left = (value & AD1843_LDA1G_MASK) >> AD1843_LDA1G_SHIFT;
821845cd29dSjmcneill right = (value & AD1843_RDA1G_MASK) >> AD1843_RDA1G_SHIFT;
822845cd29dSjmcneill if (control & MAVB_CONTROL_VOLUME_BUTTON_UP) {
823845cd29dSjmcneill control &= ~MAVB_CONTROL_VOLUME_BUTTON_UP;
824845cd29dSjmcneill if (left > 0)
825845cd29dSjmcneill left--; /* attenuation! */
826845cd29dSjmcneill if (right > 0)
827845cd29dSjmcneill right--;
828845cd29dSjmcneill }
829845cd29dSjmcneill if (control & MAVB_CONTROL_VOLUME_BUTTON_DOWN) {
830845cd29dSjmcneill control &= ~MAVB_CONTROL_VOLUME_BUTTON_DOWN;
831845cd29dSjmcneill if (left < 63)
832845cd29dSjmcneill left++;
833845cd29dSjmcneill if (right < 63)
834845cd29dSjmcneill right++;
835845cd29dSjmcneill }
836845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL, control);
837845cd29dSjmcneill
838845cd29dSjmcneill value &= ~(AD1843_LDA1G_MASK | AD1843_RDA1G_MASK);
839845cd29dSjmcneill value |= (left << AD1843_LDA1G_SHIFT);
840845cd29dSjmcneill value |= (right << AD1843_RDA1G_SHIFT);
841845cd29dSjmcneill ad1843_reg_write(sc, AD1843_DAC1_ANALOG_GAIN, value);
842845cd29dSjmcneill
843845cd29dSjmcneill callout_reset(&sc->sc_volume_button_ch,
844845cd29dSjmcneill (hz * MAVB_VOLUME_BUTTON_REPEAT_DELN) / 1000,
845845cd29dSjmcneill mavb_button_repeat, sc);
846845cd29dSjmcneill } else {
847845cd29dSjmcneill /* Enable volume button interrupts again. */
848845cd29dSjmcneill intmask = bus_space_read_8(sc->sc_st, sc->sc_isash,
849845cd29dSjmcneill MACE_ISA_INT_MASK);
850845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_isash, MACE_ISA_INT_MASK,
851845cd29dSjmcneill intmask | MACE_ISA_INT_AUDIO_SC);
852845cd29dSjmcneill }
853845cd29dSjmcneill }
854845cd29dSjmcneill
855845cd29dSjmcneill static int
mavb_intr(void * arg)856845cd29dSjmcneill mavb_intr(void *arg)
857845cd29dSjmcneill {
858845cd29dSjmcneill struct mavb_softc *sc = arg;
8591db87857Stsutsui uint64_t stat, intmask;
860845cd29dSjmcneill
8618a962f23Sjmcneill mutex_spin_enter(&sc->sc_intr_lock);
8628a962f23Sjmcneill
863845cd29dSjmcneill stat = bus_space_read_8(sc->sc_st, sc->sc_isash, MACE_ISA_INT_STATUS);
864845cd29dSjmcneill DPRINTF(MAVB_DEBUG_INTR, ("%s: mavb_intr: stat = 0x%llx\n",
865cbab9cadSchs device_xname(sc->sc_dev), stat));
866845cd29dSjmcneill
867845cd29dSjmcneill if (stat & MACE_ISA_INT_AUDIO_SC) {
868845cd29dSjmcneill /* Disable volume button interrupts. */
869845cd29dSjmcneill intmask = bus_space_read_8(sc->sc_st, sc->sc_isash,
870845cd29dSjmcneill MACE_ISA_INT_MASK);
871845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_isash, MACE_ISA_INT_MASK,
872845cd29dSjmcneill intmask & ~MACE_ISA_INT_AUDIO_SC);
873845cd29dSjmcneill
874845cd29dSjmcneill callout_reset(&sc->sc_volume_button_ch,
875845cd29dSjmcneill (hz * MAVB_VOLUME_BUTTON_REPEAT_DEL1) / 1000,
876845cd29dSjmcneill mavb_button_repeat, sc);
877845cd29dSjmcneill }
878845cd29dSjmcneill
879845cd29dSjmcneill if (stat & MACE_ISA_INT_AUDIO_DMA2)
880845cd29dSjmcneill mavb_dma_output(sc);
881845cd29dSjmcneill
8828a962f23Sjmcneill mutex_spin_exit(&sc->sc_intr_lock);
8838a962f23Sjmcneill
884845cd29dSjmcneill return 1;
885845cd29dSjmcneill }
886845cd29dSjmcneill
887845cd29dSjmcneill int
mavb_match(device_t parent,cfdata_t match,void * aux)888cbab9cadSchs mavb_match(device_t parent, cfdata_t match, void *aux)
889845cd29dSjmcneill {
8901db87857Stsutsui
8911db87857Stsutsui return 1;
892845cd29dSjmcneill }
893845cd29dSjmcneill
894845cd29dSjmcneill void
mavb_attach(device_t parent,device_t self,void * aux)895cbab9cadSchs mavb_attach(device_t parent, device_t self, void *aux)
896845cd29dSjmcneill {
897cbab9cadSchs struct mavb_softc *sc = device_private(self);
898845cd29dSjmcneill struct mace_attach_args *maa = aux;
899845cd29dSjmcneill bus_dma_segment_t seg;
9001db87857Stsutsui uint64_t control;
9011db87857Stsutsui uint16_t value;
902e622eac4Sisaki int rseg;
903845cd29dSjmcneill
904cbab9cadSchs sc->sc_dev = self;
905cbab9cadSchs
9068a962f23Sjmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
9078a962f23Sjmcneill mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
9088a962f23Sjmcneill
909845cd29dSjmcneill sc->sc_st = maa->maa_st;
910845cd29dSjmcneill if (bus_space_subregion(sc->sc_st, maa->maa_sh, maa->maa_offset,
911845cd29dSjmcneill 0, &sc->sc_sh) != 0) {
912845cd29dSjmcneill printf(": can't map i/o space\n");
913845cd29dSjmcneill return;
914845cd29dSjmcneill }
915845cd29dSjmcneill
916845cd29dSjmcneill /* XXX We need access to some of the MACE ISA registers. */
917845cd29dSjmcneill if (bus_space_subregion(sc->sc_st, maa->maa_sh, 0, 0,
918845cd29dSjmcneill &sc->sc_isash) != 0) {
919845cd29dSjmcneill printf(": can't map isa i/o space\n");
920845cd29dSjmcneill return;
921845cd29dSjmcneill }
922845cd29dSjmcneill
923845cd29dSjmcneill /* Set up DMA structures. */
924845cd29dSjmcneill sc->sc_dmat = maa->maa_dmat;
925845cd29dSjmcneill if (bus_dmamap_create(sc->sc_dmat, 4 * MAVB_ISA_RING_SIZE, 1,
926845cd29dSjmcneill 4 * MAVB_ISA_RING_SIZE, 0, 0, &sc->sc_dmamap)) {
927845cd29dSjmcneill printf(": can't create MACE ISA DMA map\n");
928845cd29dSjmcneill return;
929845cd29dSjmcneill }
930845cd29dSjmcneill
931845cd29dSjmcneill if (bus_dmamem_alloc(sc->sc_dmat, 4 * MAVB_ISA_RING_SIZE,
932845cd29dSjmcneill MACE_ISA_RING_ALIGN, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
933845cd29dSjmcneill printf(": can't allocate ring buffer\n");
934845cd29dSjmcneill return;
935845cd29dSjmcneill }
936845cd29dSjmcneill
937845cd29dSjmcneill if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, 4 * MAVB_ISA_RING_SIZE,
938845cd29dSjmcneill (void *)&sc->sc_ring, BUS_DMA_COHERENT)) {
939845cd29dSjmcneill printf(": can't map ring buffer\n");
940845cd29dSjmcneill return;
941845cd29dSjmcneill }
942845cd29dSjmcneill
943845cd29dSjmcneill if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ring,
944845cd29dSjmcneill 4 * MAVB_ISA_RING_SIZE, NULL, BUS_DMA_NOWAIT)) {
945845cd29dSjmcneill printf(": can't load MACE ISA DMA map\n");
946845cd29dSjmcneill return;
947845cd29dSjmcneill }
948845cd29dSjmcneill
949845cd29dSjmcneill sc->sc_ring += MAVB_ISA_RING_SIZE; /* XXX */
950845cd29dSjmcneill
951845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_isash, MACE_ISA_RINGBASE,
952845cd29dSjmcneill sc->sc_dmamap->dm_segs[0].ds_addr);
953845cd29dSjmcneill
954845cd29dSjmcneill /* Establish interrupt. */
955845cd29dSjmcneill cpu_intr_establish(maa->maa_intr, maa->maa_intrmask,
956845cd29dSjmcneill mavb_intr, sc);
957845cd29dSjmcneill
958845cd29dSjmcneill control = bus_space_read_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL);
959845cd29dSjmcneill if (!(control & MAVB_CONTROL_CODEC_PRESENT)) {
960845cd29dSjmcneill printf(": no codec present\n");
961845cd29dSjmcneill return;
962845cd29dSjmcneill }
963845cd29dSjmcneill
964845cd29dSjmcneill /* 2. Assert the RESET signal. */
965845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL,
966845cd29dSjmcneill MAVB_CONTROL_RESET);
967845cd29dSjmcneill delay(1); /* at least 100 ns */
968845cd29dSjmcneill
969845cd29dSjmcneill /* 3. Deassert the RESET signal and enter a wait period to
970845cd29dSjmcneill allow the AD1843 internal clocks and the external
971845cd29dSjmcneill crystal oscillator to stabilize. */
972845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CONTROL, 0);
973845cd29dSjmcneill delay(800); /* typically 400 us to 800 us */
974845cd29dSjmcneill if (ad1843_reg_read(sc, AD1843_CODEC_STATUS) & AD1843_INIT) {
975845cd29dSjmcneill printf(": codec not ready\n");
976845cd29dSjmcneill return;
977845cd29dSjmcneill }
978845cd29dSjmcneill
979845cd29dSjmcneill /* 4. Put the conversion sources into standby. */
980845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_FUNDAMENTAL_SETTINGS);
981845cd29dSjmcneill ad1843_reg_write(sc, AD1843_FUNDAMENTAL_SETTINGS,
982845cd29dSjmcneill value & ~AD1843_PDNI);
983845cd29dSjmcneill delay (500000); /* approximately 474 ms */
984845cd29dSjmcneill if (ad1843_reg_read(sc, AD1843_CODEC_STATUS) & AD1843_PDNO) {
985845cd29dSjmcneill printf(": can't power up conversion resources\n");
986845cd29dSjmcneill return;
987845cd29dSjmcneill }
988845cd29dSjmcneill
989845cd29dSjmcneill /* 5. Power up the clock generators and enable clock output pins. */
990845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_FUNDAMENTAL_SETTINGS);
991845cd29dSjmcneill ad1843_reg_write(sc, AD1843_FUNDAMENTAL_SETTINGS, value | AD1843_C2EN);
992845cd29dSjmcneill
993845cd29dSjmcneill /* 6. Configure conversion resources while they are in standby. */
994845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_CHANNEL_SAMPLE_RATE);
995845cd29dSjmcneill ad1843_reg_write(sc, AD1843_CHANNEL_SAMPLE_RATE,
996845cd29dSjmcneill value | (2 << AD1843_DA1C_SHIFT));
997845cd29dSjmcneill
998845cd29dSjmcneill /* 7. Enable conversion resources. */
999845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_CHANNEL_POWER_DOWN);
1000845cd29dSjmcneill ad1843_reg_write(sc, AD1843_CHANNEL_POWER_DOWN,
1001845cd29dSjmcneill value | (AD1843_DA1EN | AD1843_AAMEN));
1002845cd29dSjmcneill
1003845cd29dSjmcneill /* 8. Configure conversion resources while they are enabled. */
1004845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_DAC1_ANALOG_GAIN);
1005845cd29dSjmcneill ad1843_reg_write(sc, AD1843_DAC1_ANALOG_GAIN,
1006845cd29dSjmcneill value & ~(AD1843_LDA1GM | AD1843_RDA1GM));
1007845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_DAC1_DIGITAL_GAIN);
1008845cd29dSjmcneill ad1843_reg_write(sc, AD1843_DAC1_DIGITAL_GAIN,
1009845cd29dSjmcneill value & ~(AD1843_LDA1AM | AD1843_RDA1AM));
1010845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_MISC_SETTINGS);
1011845cd29dSjmcneill ad1843_reg_write(sc, AD1843_MISC_SETTINGS,
1012845cd29dSjmcneill value & ~(AD1843_HPOM | AD1843_MNOM));
1013845cd29dSjmcneill
1014845cd29dSjmcneill value = ad1843_reg_read(sc, AD1843_CODEC_STATUS);
1015845cd29dSjmcneill printf(": AD1843 rev %d\n", (u_int)value & AD1843_REVISION_MASK);
1016845cd29dSjmcneill
1017845cd29dSjmcneill sc->sc_play_rate = 48000;
1018845cd29dSjmcneill sc->sc_play_format = AD1843_PCM8;
1019845cd29dSjmcneill
102088ab7da9Sad callout_init(&sc->sc_volume_button_ch, 0);
1021845cd29dSjmcneill
1022cbab9cadSchs audio_attach_mi(&mavb_sa_hw_if, sc, self);
1023845cd29dSjmcneill
1024845cd29dSjmcneill return;
1025845cd29dSjmcneill }
1026845cd29dSjmcneill
10271db87857Stsutsui uint16_t
ad1843_reg_read(struct mavb_softc * sc,ad1843_addr_t addr)1028845cd29dSjmcneill ad1843_reg_read(struct mavb_softc *sc, ad1843_addr_t addr)
1029845cd29dSjmcneill {
1030845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CODEC_CONTROL,
1031845cd29dSjmcneill (addr & MAVB_CODEC_ADDRESS_MASK) << MAVB_CODEC_ADDRESS_SHIFT |
1032845cd29dSjmcneill MAVB_CODEC_READ);
1033845cd29dSjmcneill delay(200);
1034845cd29dSjmcneill return bus_space_read_8(sc->sc_st, sc->sc_sh, MAVB_CODEC_STATUS);
1035845cd29dSjmcneill }
1036845cd29dSjmcneill
10371db87857Stsutsui uint16_t
ad1843_reg_write(struct mavb_softc * sc,ad1843_addr_t addr,uint16_t value)10381db87857Stsutsui ad1843_reg_write(struct mavb_softc *sc, ad1843_addr_t addr, uint16_t value)
1039845cd29dSjmcneill {
1040845cd29dSjmcneill bus_space_write_8(sc->sc_st, sc->sc_sh, MAVB_CODEC_CONTROL,
1041845cd29dSjmcneill (addr & MAVB_CODEC_ADDRESS_MASK) << MAVB_CODEC_ADDRESS_SHIFT |
1042845cd29dSjmcneill (value & MAVB_CODEC_WORD_MASK) << MAVB_CODEC_WORD_SHIFT);
1043845cd29dSjmcneill delay(200);
1044845cd29dSjmcneill return bus_space_read_8(sc->sc_st, sc->sc_sh, MAVB_CODEC_STATUS);
1045845cd29dSjmcneill }
1046845cd29dSjmcneill
1047845cd29dSjmcneill void
ad1843_dump_regs(struct mavb_softc * sc)1048845cd29dSjmcneill ad1843_dump_regs(struct mavb_softc *sc)
1049845cd29dSjmcneill {
10501db87857Stsutsui uint16_t addr;
1051845cd29dSjmcneill
1052845cd29dSjmcneill for (addr = 0; addr < AD1843_NREGS; addr++)
1053845cd29dSjmcneill printf("%d: 0x%04x\n", addr, ad1843_reg_read(sc, addr));
1054845cd29dSjmcneill }
1055