xref: /netbsd-src/sys/arch/hpcmips/vr/vraiu.c (revision df83eae357e2d04f8a1b60ea74308250f6ba675c)
1*df83eae3Sskrll /*	$NetBSD: vraiu.c,v 1.20 2021/01/13 06:39:46 skrll Exp $	*/
2fddeb95fShamajima 
3fddeb95fShamajima /*
4fddeb95fShamajima  * Copyright (c) 2001 HAMAJIMA Katsuomi. All rights reserved.
5fddeb95fShamajima  *
6fddeb95fShamajima  * Redistribution and use in source and binary forms, with or without
7fddeb95fShamajima  * modification, are permitted provided that the following conditions
8fddeb95fShamajima  * are met:
9fddeb95fShamajima  * 1. Redistributions of source code must retain the above copyright
10fddeb95fShamajima  *    notice, this list of conditions and the following disclaimer.
11fddeb95fShamajima  * 2. Redistributions in binary form must reproduce the above copyright
12fddeb95fShamajima  *    notice, this list of conditions and the following disclaimer in the
13fddeb95fShamajima  *    documentation and/or other materials provided with the distribution.
14fddeb95fShamajima  *
15fddeb95fShamajima  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16fddeb95fShamajima  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17fddeb95fShamajima  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18fddeb95fShamajima  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19fddeb95fShamajima  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20fddeb95fShamajima  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21fddeb95fShamajima  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22fddeb95fShamajima  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23fddeb95fShamajima  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24fddeb95fShamajima  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25fddeb95fShamajima  * SUCH DAMAGE.
26fddeb95fShamajima  */
27fddeb95fShamajima 
280c82163cSlukem #include <sys/cdefs.h>
29*df83eae3Sskrll __KERNEL_RCSID(0, "$NetBSD: vraiu.c,v 1.20 2021/01/13 06:39:46 skrll Exp $");
300c82163cSlukem 
31fddeb95fShamajima #include <sys/param.h>
32fddeb95fShamajima #include <sys/systm.h>
33fddeb95fShamajima #include <sys/device.h>
34fddeb95fShamajima #include <sys/bswap.h>
35fddeb95fShamajima 
36fddeb95fShamajima #include <machine/cpu.h>
37fddeb95fShamajima #include <machine/intr.h>
38fddeb95fShamajima #include <machine/bus.h>
39fddeb95fShamajima #include <machine/platid.h>
40fddeb95fShamajima #include <machine/platid_mask.h>
41fddeb95fShamajima #include <machine/config_hook.h>
42fddeb95fShamajima 
43fddeb95fShamajima #include <sys/audioio.h>
44e622eac4Sisaki #include <dev/audio/audio_if.h>
45fddeb95fShamajima 
46fddeb95fShamajima #include <hpcmips/vr/vr.h>
47fddeb95fShamajima #include <hpcmips/vr/vripif.h>
48fddeb95fShamajima #include <hpcmips/vr/icureg.h>
49fddeb95fShamajima #include <hpcmips/vr/cmureg.h>
50fddeb95fShamajima #include <hpcmips/vr/vraiureg.h>
51fddeb95fShamajima 
52fddeb95fShamajima #ifdef VRAIU_DEBUG
53fddeb95fShamajima int vraiu_debug = VRAIU_DEBUG;
54fddeb95fShamajima #define DPRINTFN(n,x) if (vraiu_debug>(n)) printf x;
55fddeb95fShamajima #else
56fddeb95fShamajima #define DPRINTFN(n,x)
57fddeb95fShamajima #endif
58fddeb95fShamajima 
59fddeb95fShamajima #define AUDIO_BUF_SIZE 2048
60fddeb95fShamajima 
61fddeb95fShamajima struct vraiu_softc {
62cbab9cadSchs 	device_t		sc_dev;
638a962f23Sjmcneill 	kmutex_t		sc_lock;
648a962f23Sjmcneill 	kmutex_t		sc_intr_lock;
65fddeb95fShamajima 	bus_space_tag_t		sc_iot;
66fddeb95fShamajima 	bus_space_handle_t	sc_ioh;
67fddeb95fShamajima 	bus_dma_tag_t		sc_dmat;
68fddeb95fShamajima 	bus_dmamap_t		sc_dmap;
69fddeb95fShamajima 	vrip_chipset_tag_t	sc_vrip;
70fddeb95fShamajima 	vrdcu_chipset_tag_t	sc_dc;
71fddeb95fShamajima 	vrdmaau_chipset_tag_t	sc_ac;
72fddeb95fShamajima 	vrcmu_chipset_tag_t	sc_cc;
73fddeb95fShamajima 	void			*sc_handler;
741ffa7b76Swiz 	u_short	*sc_buf;	/* DMA buffer pointer */
75fddeb95fShamajima 	u_int	sc_rate;	/* sampling rate */
768c56c583Sjmcneill 	u_char	sc_volume;	/* volume */
77fddeb95fShamajima 	void	(*sc_intr)(void *);	/* interrupt routine */
78fddeb95fShamajima 	void	*sc_intrdata;		/* interrupt data */
79fddeb95fShamajima };
80fddeb95fShamajima 
81cbab9cadSchs int vraiu_match(device_t, cfdata_t, void *);
82cbab9cadSchs void vraiu_attach(device_t, device_t, void *);
83fddeb95fShamajima int vraiu_intr(void *);
84fddeb95fShamajima 
85cbab9cadSchs CFATTACH_DECL_NEW(vraiu, sizeof(struct vraiu_softc),
86c5e91d44Sthorpej     vraiu_match, vraiu_attach, NULL, NULL);
87fddeb95fShamajima 
88fddeb95fShamajima struct audio_device aiu_device = {
89fddeb95fShamajima 	"VR4121 AIU",
90fddeb95fShamajima 	"0.1",
91fddeb95fShamajima 	"aiu"
92fddeb95fShamajima };
93fddeb95fShamajima 
94e622eac4Sisaki const struct audio_format vraiu_formats = {
95e622eac4Sisaki 	.mode		= AUMODE_PLAY,
96e622eac4Sisaki 	.encoding	= AUDIO_ENCODING_SLINEAR_NE,
97e622eac4Sisaki 	.validbits	= 10,
98e622eac4Sisaki 	.precision	= 16,
99e622eac4Sisaki 	.channels	= 1,
100e622eac4Sisaki 	.channel_mask	= AUFMT_MONAURAL,
101e622eac4Sisaki 	.frequency_type	= 4,
102e622eac4Sisaki 	.frequency	= { 8000, 11025, 22050, 44100 },
103e622eac4Sisaki };
104e622eac4Sisaki 
105fddeb95fShamajima /*
106fddeb95fShamajima  * Define our interface to the higher level audio driver.
107fddeb95fShamajima  */
108e622eac4Sisaki int vraiu_query_format(void *, audio_format_query_t *);
10923b5d914Skent int vraiu_round_blocksize(void *, int, int, const audio_params_t *);
110fddeb95fShamajima int vraiu_commit_settings(void *);
111fddeb95fShamajima int vraiu_init_output(void *, void*, int);
112fddeb95fShamajima int vraiu_start_output(void *, void *, int, void (*)(void *), void *);
113fddeb95fShamajima int vraiu_halt_output(void *);
114fddeb95fShamajima int vraiu_getdev(void *, struct audio_device *);
115fddeb95fShamajima int vraiu_set_port(void *, mixer_ctrl_t *);
116fddeb95fShamajima int vraiu_get_port(void *, mixer_ctrl_t *);
117fddeb95fShamajima int vraiu_query_devinfo(void *, mixer_devinfo_t *);
118e622eac4Sisaki int vraiu_set_format(void *, int,
119e622eac4Sisaki     const audio_params_t *, const audio_params_t *,
120e622eac4Sisaki     audio_filter_reg_t *, audio_filter_reg_t *);
121fddeb95fShamajima int vraiu_get_props(void *);
1228a962f23Sjmcneill void vraiu_get_locks(void *, kmutex_t **, kmutex_t **);
123fddeb95fShamajima 
12418f717bbSyamt const struct audio_hw_if vraiu_hw_if = {
125e622eac4Sisaki 	.query_format		= vraiu_query_format,
126e622eac4Sisaki 	.set_format		= vraiu_set_format,
1276291b134Sisaki 	.round_blocksize	= vraiu_round_blocksize,
1286291b134Sisaki 	.commit_settings	= vraiu_commit_settings,
1296291b134Sisaki 	.init_output		= vraiu_init_output,
1306291b134Sisaki 	.start_output		= vraiu_start_output,
1316291b134Sisaki 	.halt_output		= vraiu_halt_output,
1326291b134Sisaki 	.getdev			= vraiu_getdev,
1336291b134Sisaki 	.set_port		= vraiu_set_port,
1346291b134Sisaki 	.get_port		= vraiu_get_port,
1356291b134Sisaki 	.query_devinfo		= vraiu_query_devinfo,
1366291b134Sisaki 	.get_props		= vraiu_get_props,
1376291b134Sisaki 	.get_locks		= vraiu_get_locks,
138fddeb95fShamajima };
139fddeb95fShamajima 
140fddeb95fShamajima /*
141fddeb95fShamajima  * convert to 1ch 10bit unsigned PCM data.
142fddeb95fShamajima  */
143fddeb95fShamajima static void vraiu_slinear16_1(struct vraiu_softc *, u_short *, void *, int);
144fddeb95fShamajima 
145fddeb95fShamajima int
vraiu_match(device_t parent,cfdata_t cf,void * aux)146cbab9cadSchs vraiu_match(device_t parent, cfdata_t cf, void *aux)
147fddeb95fShamajima {
148fddeb95fShamajima 	return 1;
149fddeb95fShamajima }
150fddeb95fShamajima 
151fddeb95fShamajima void
vraiu_attach(device_t parent,device_t self,void * aux)152cbab9cadSchs vraiu_attach(device_t parent, device_t self, void *aux)
153fddeb95fShamajima {
15493293b9eSkent 	struct vrip_attach_args *va;
15593293b9eSkent 	struct vraiu_softc *sc;
156fddeb95fShamajima 	bus_dma_segment_t segs;
157fddeb95fShamajima 	int rsegs;
158fddeb95fShamajima 
15993293b9eSkent 	va = aux;
160cbab9cadSchs 	sc = device_private(self);
161cbab9cadSchs 	sc->sc_dev = self;
162fddeb95fShamajima 	sc->sc_intr = NULL;
163fddeb95fShamajima 	sc->sc_iot = va->va_iot;
164fddeb95fShamajima 	sc->sc_vrip = va->va_vc;
165fddeb95fShamajima 	sc->sc_cc = va->va_cc;
166fddeb95fShamajima 	sc->sc_dc = va->va_dc;
167fddeb95fShamajima 	sc->sc_ac = va->va_ac;
168fddeb95fShamajima 	sc->sc_dmat = &vrdcu_bus_dma_tag;
1698c56c583Sjmcneill 	sc->sc_volume = 127;
1708a962f23Sjmcneill 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1718de08fa9Smrg 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
172fddeb95fShamajima 
173fddeb95fShamajima 	if (!sc->sc_cc) {
174fddeb95fShamajima 		printf(" not configured: cmu not found\n");
175fddeb95fShamajima 		return;
176fddeb95fShamajima 	}
177fddeb95fShamajima 	if (!sc->sc_dc) {
178fddeb95fShamajima 		printf(" not configured: dcu not found\n");
179fddeb95fShamajima 		return;
180fddeb95fShamajima 	}
181fddeb95fShamajima 	if (!sc->sc_ac) {
182fddeb95fShamajima 		printf(" not configured: dmaau not found\n");
183fddeb95fShamajima 		return;
184fddeb95fShamajima 	}
185fddeb95fShamajima 	if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
186fddeb95fShamajima 			  0 /* no flags */, &sc->sc_ioh)) {
187fddeb95fShamajima 		printf(": can't map i/o space\n");
188fddeb95fShamajima 		return;
189fddeb95fShamajima 	}
190fddeb95fShamajima 
191fddeb95fShamajima 	/* install interrupt handler and enable interrupt */
192fddeb95fShamajima 	if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit,
1938de08fa9Smrg 	    0, IPL_AUDIO, vraiu_intr, sc))) {
194fddeb95fShamajima 		printf(": can't map interrupt line.\n");
195fddeb95fShamajima 		return;
196fddeb95fShamajima 	}
197fddeb95fShamajima 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, (AIUINT_INTMEND | \
198fddeb95fShamajima 							 AIUINT_INTM | \
199fddeb95fShamajima 							 AIUINT_INTMIDLE | \
200fddeb95fShamajima 							 AIUINT_INTMST | \
201fddeb95fShamajima 							 AIUINT_INTSEND | \
202fddeb95fShamajima 							 AIUINT_INTS | \
203fddeb95fShamajima 							 AIUINT_INTSIDLE), 0);
204fddeb95fShamajima 
205fddeb95fShamajima 	if (bus_dmamem_alloc(sc->sc_dmat, AUDIO_BUF_SIZE, 0, 0, &segs, 1,
2068a962f23Sjmcneill 			     &rsegs, BUS_DMA_WAITOK)) {
207fddeb95fShamajima 		printf(": can't allocate memory.\n");
208fddeb95fShamajima 		return;
209fddeb95fShamajima 	}
210fddeb95fShamajima 	if (bus_dmamem_map(sc->sc_dmat, &segs, rsegs, AUDIO_BUF_SIZE,
21153524e44Schristos 			   (void **)&sc->sc_buf,
2128a962f23Sjmcneill 			   BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
213fddeb95fShamajima 		printf(": can't map memory.\n");
214fddeb95fShamajima 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
215fddeb95fShamajima 		return;
216fddeb95fShamajima 	}
217fddeb95fShamajima 	if (bus_dmamap_create(sc->sc_dmat, AUDIO_BUF_SIZE, 1, AUDIO_BUF_SIZE,
2188a962f23Sjmcneill 			      0, BUS_DMA_WAITOK, &sc->sc_dmap)) {
219fddeb95fShamajima 		printf(": can't create DMA map.\n");
22053524e44Schristos 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
221fddeb95fShamajima 				 AUDIO_BUF_SIZE);
222fddeb95fShamajima 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
223fddeb95fShamajima 		return;
224fddeb95fShamajima 	}
225fddeb95fShamajima 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, sc->sc_buf,
2268a962f23Sjmcneill 				   AUDIO_BUF_SIZE, NULL, BUS_DMA_WAITOK)) {
227fddeb95fShamajima 		printf(": can't load DMA map.\n");
228fddeb95fShamajima 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
22953524e44Schristos 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
230fddeb95fShamajima 				 AUDIO_BUF_SIZE);
231fddeb95fShamajima 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
232fddeb95fShamajima 		return;
233fddeb95fShamajima 	}
234fddeb95fShamajima 	if (sc->sc_ac->ac_set_aiuout(sc->sc_ac, sc->sc_buf)) {
235fddeb95fShamajima 		printf(": can't set DMA address.\n");
236fddeb95fShamajima 		bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
237fddeb95fShamajima 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
23853524e44Schristos 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
239fddeb95fShamajima 				 AUDIO_BUF_SIZE);
240fddeb95fShamajima 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
241fddeb95fShamajima 		return;
242fddeb95fShamajima 	}
243fddeb95fShamajima 	printf("\n");
244fddeb95fShamajima 
245fddeb95fShamajima 	sc->sc_rate = SPS8000;
246fddeb95fShamajima 	DPRINTFN(1, ("vraiu_attach: reset AIU\n"))
247fddeb95fShamajima 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIURST);
248fddeb95fShamajima 	/* attach audio subsystem */
249cbab9cadSchs 	audio_attach_mi(&vraiu_hw_if, sc, self);
250fddeb95fShamajima }
251fddeb95fShamajima 
252fddeb95fShamajima int
vraiu_query_format(void * self,audio_format_query_t * afp)253e622eac4Sisaki vraiu_query_format(void *self, audio_format_query_t *afp)
254fddeb95fShamajima {
255fddeb95fShamajima 
256e622eac4Sisaki 	return audio_query_format(&vraiu_formats, 1, afp);
257fddeb95fShamajima }
258fddeb95fShamajima 
259fddeb95fShamajima int
vraiu_set_format(void * self,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)260e622eac4Sisaki vraiu_set_format(void *self, int setmode,
261e622eac4Sisaki 		 const audio_params_t *play, const audio_params_t *rec,
262e622eac4Sisaki 		 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
263fddeb95fShamajima {
26493293b9eSkent 	struct vraiu_softc *sc;
265fddeb95fShamajima 
266e622eac4Sisaki 	DPRINTFN(1, ("%s: %ubit, %uch, %uHz, encoding %u\n", __func__,
267fddeb95fShamajima 		     play->precision, play->channels, play->sample_rate,
268fddeb95fShamajima 		     play->encoding));
26993293b9eSkent 	sc = self;
270e622eac4Sisaki 
271fddeb95fShamajima 	switch (play->sample_rate) {
272fddeb95fShamajima 	case 8000:
273fddeb95fShamajima 		sc->sc_rate = SPS8000;
274fddeb95fShamajima 		break;
275fddeb95fShamajima 	case 11025:
276fddeb95fShamajima 		sc->sc_rate = SPS11025;
277fddeb95fShamajima 		break;
278fddeb95fShamajima 	case 22050:
279fddeb95fShamajima 		sc->sc_rate = SPS22050;
280fddeb95fShamajima 		break;
281fddeb95fShamajima 	case 44100:
282fddeb95fShamajima 		sc->sc_rate = SPS44100;
283fddeb95fShamajima 		break;
284fddeb95fShamajima 	default:
285e622eac4Sisaki 		/* NOTREACHED */
286e622eac4Sisaki 		panic("%s: rate error (%d)\n", __func__, play->sample_rate);
287fddeb95fShamajima 	}
288fddeb95fShamajima 
289fddeb95fShamajima 	return 0;
290fddeb95fShamajima }
291fddeb95fShamajima 
292fddeb95fShamajima int
vraiu_round_blocksize(void * self,int bs,int mode,const audio_params_t * param)29323b5d914Skent vraiu_round_blocksize(void *self, int bs, int mode, const audio_params_t *param)
294fddeb95fShamajima {
295e622eac4Sisaki 	return AUDIO_BUF_SIZE;
296fddeb95fShamajima }
297fddeb95fShamajima 
298fddeb95fShamajima int
vraiu_commit_settings(void * self)299fddeb95fShamajima vraiu_commit_settings(void *self)
300fddeb95fShamajima {
30193293b9eSkent 	struct vraiu_softc *sc;
302fddeb95fShamajima 	int err;
303fddeb95fShamajima 
304fddeb95fShamajima 	DPRINTFN(1, ("vraiu_commit_settings\n"));
30593293b9eSkent 	sc = self;
306fddeb95fShamajima 
307fddeb95fShamajima 	DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
308fddeb95fShamajima 		     sc->sc_rate))
309fddeb95fShamajima 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
310fddeb95fShamajima 	DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
311fddeb95fShamajima 	if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
312fddeb95fShamajima 		DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
313fddeb95fShamajima 		return err;
314fddeb95fShamajima 	}
315fddeb95fShamajima 	DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
316fddeb95fShamajima 	if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
317fddeb95fShamajima 		sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
3181ffa7b76Swiz 		DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
319fddeb95fShamajima 		return err;
320fddeb95fShamajima 	}
321fddeb95fShamajima 	DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
322fddeb95fShamajima 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
323fddeb95fShamajima 	return 0;
324fddeb95fShamajima }
325fddeb95fShamajima 
326fddeb95fShamajima int
vraiu_init_output(void * self,void * buffer,int size)327fddeb95fShamajima vraiu_init_output(void *self, void *buffer, int size)
328fddeb95fShamajima {
32993293b9eSkent 	struct vraiu_softc *sc;
330fddeb95fShamajima 
331fddeb95fShamajima 	DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
33293293b9eSkent 	sc = self;
333fddeb95fShamajima 	sc->sc_intr = NULL;
334fddeb95fShamajima 	DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
335fddeb95fShamajima 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
336fddeb95fShamajima 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
337fddeb95fShamajima 	DPRINTFN(1, ("vraiu_init_output: start output\n"))
338fddeb95fShamajima 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
339fddeb95fShamajima 	return 0;
340fddeb95fShamajima }
341fddeb95fShamajima 
342fddeb95fShamajima int
vraiu_start_output(void * self,void * block,int bsize,void (* intr)(void *),void * intrarg)343fddeb95fShamajima vraiu_start_output(void *self, void *block, int bsize,
344fddeb95fShamajima 		   void (*intr)(void *), void *intrarg)
345fddeb95fShamajima {
34693293b9eSkent 	struct vraiu_softc *sc;
347fddeb95fShamajima 
348fddeb95fShamajima 	DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
349fddeb95fShamajima 		     block, bsize));
35093293b9eSkent 	sc = self;
351e622eac4Sisaki 	vraiu_slinear16_1(sc, sc->sc_buf, block, bsize);
352fddeb95fShamajima 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
353fddeb95fShamajima 			BUS_DMASYNC_PREWRITE);
354fddeb95fShamajima 	sc->sc_intr = intr;
355fddeb95fShamajima 	sc->sc_intrdata = intrarg;
356fddeb95fShamajima 	/* clear interrupt status */
357fddeb95fShamajima 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
358fddeb95fShamajima 			  SENDINTR | SINTR | SIDLEINTR);
359fddeb95fShamajima 	/* enable interrupt */
360fddeb95fShamajima 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
361fddeb95fShamajima 	return 0;
362fddeb95fShamajima }
363fddeb95fShamajima 
364fddeb95fShamajima int
vraiu_intr(void * self)365fddeb95fShamajima vraiu_intr(void* self)
366fddeb95fShamajima {
36793293b9eSkent 	struct vraiu_softc *sc;
36893293b9eSkent 	uint32_t reg;
369fddeb95fShamajima 
370fddeb95fShamajima 	DPRINTFN(2, ("vraiu_intr"));
37193293b9eSkent 	sc = self;
3728a962f23Sjmcneill 
3738a962f23Sjmcneill 	mutex_spin_enter(&sc->sc_intr_lock);
3748a962f23Sjmcneill 
375fddeb95fShamajima 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
376fddeb95fShamajima 	vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, &reg);
377fddeb95fShamajima 	if (reg & AIUINT_INTSEND) {
378fddeb95fShamajima 		DPRINTFN(2, (": AIUINT_INTSEND"));
379fddeb95fShamajima 		if (sc->sc_intr) {
38093293b9eSkent 			void (*intr)(void *);
38193293b9eSkent 			intr = sc->sc_intr;
382fddeb95fShamajima 			sc->sc_intr = NULL;
383fddeb95fShamajima 			(*(intr))(sc->sc_intrdata);
384fddeb95fShamajima 		}
385fddeb95fShamajima 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
386fddeb95fShamajima 	}
387fddeb95fShamajima 	DPRINTFN(2, ("\n"));
3888a962f23Sjmcneill 
3898a962f23Sjmcneill 	mutex_spin_exit(&sc->sc_intr_lock);
3908a962f23Sjmcneill 
391fddeb95fShamajima 	return 0;
392fddeb95fShamajima }
393fddeb95fShamajima 
394fddeb95fShamajima int
vraiu_halt_output(void * self)395fddeb95fShamajima vraiu_halt_output(void *self)
396fddeb95fShamajima {
39793293b9eSkent 	struct vraiu_softc *sc;
398fddeb95fShamajima 
399fddeb95fShamajima 	DPRINTFN(1, ("vraiu_halt_output\n"));
40093293b9eSkent 	sc =self;
401fddeb95fShamajima 	DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
402fddeb95fShamajima 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
403fddeb95fShamajima 	DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
404fddeb95fShamajima 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
405fddeb95fShamajima 	DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
406fddeb95fShamajima 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
407fddeb95fShamajima 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
408fddeb95fShamajima 	DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
409fddeb95fShamajima 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
410fddeb95fShamajima 	DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
411fddeb95fShamajima 	sc->sc_dc->dc_disable(sc->sc_dc);
412fddeb95fShamajima 	DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
413fddeb95fShamajima 	sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
414fddeb95fShamajima 	sc->sc_intr = NULL;
415fddeb95fShamajima 	return 0;
416fddeb95fShamajima }
417fddeb95fShamajima 
418fddeb95fShamajima int
vraiu_getdev(void * self,struct audio_device * ret)419fddeb95fShamajima vraiu_getdev(void *self, struct audio_device *ret)
420fddeb95fShamajima {
421fddeb95fShamajima 
42293293b9eSkent 	DPRINTFN(3, ("vraiu_getdev\n"));
423fddeb95fShamajima 	*ret = aiu_device;
424fddeb95fShamajima 	return 0;
425fddeb95fShamajima }
426fddeb95fShamajima 
427fddeb95fShamajima int
vraiu_set_port(void * self,mixer_ctrl_t * mc)428fddeb95fShamajima vraiu_set_port(void *self, mixer_ctrl_t *mc)
429fddeb95fShamajima {
43093293b9eSkent 	struct vraiu_softc *sc;
431fddeb95fShamajima 
43293293b9eSkent 	DPRINTFN(3, ("vraiu_set_port\n"));
43393293b9eSkent 	sc = self;
4348c56c583Sjmcneill 	/* software mixer, 1ch */
4358c56c583Sjmcneill 	if (mc->dev == 0) {
4368c56c583Sjmcneill 		if (mc->type != AUDIO_MIXER_VALUE)
4378c56c583Sjmcneill 			return EINVAL;
4388c56c583Sjmcneill 		if (mc->un.value.num_channels != 1)
4398c56c583Sjmcneill 			return EINVAL;
4408c56c583Sjmcneill 		sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
4418c56c583Sjmcneill 		return 0;
4428c56c583Sjmcneill 	}
4438c56c583Sjmcneill 
444fddeb95fShamajima 	return EINVAL;
445fddeb95fShamajima }
446fddeb95fShamajima 
447fddeb95fShamajima int
vraiu_get_port(void * self,mixer_ctrl_t * mc)448fddeb95fShamajima vraiu_get_port(void *self, mixer_ctrl_t *mc)
449fddeb95fShamajima {
45093293b9eSkent 	struct vraiu_softc *sc;
451fddeb95fShamajima 
45293293b9eSkent 	DPRINTFN(3, ("vraiu_get_port\n"));
45393293b9eSkent 	sc = self;
4548c56c583Sjmcneill 	/* software mixer, 1ch */
4558c56c583Sjmcneill 	if (mc->dev == 0) {
4568c56c583Sjmcneill 		if (mc->un.value.num_channels != 1)
4578c56c583Sjmcneill 			return EINVAL;
4588c56c583Sjmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume;
4598c56c583Sjmcneill 		return 0;
4608c56c583Sjmcneill 	}
4618c56c583Sjmcneill 
462fddeb95fShamajima 	return EINVAL;
463fddeb95fShamajima }
464fddeb95fShamajima 
465fddeb95fShamajima int
vraiu_query_devinfo(void * self,mixer_devinfo_t * di)466fddeb95fShamajima vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
467fddeb95fShamajima {
468fddeb95fShamajima 
46993293b9eSkent 	DPRINTFN(3, ("vraiu_query_devinfo\n"));
4708c56c583Sjmcneill 	/* software mixer, 1ch */
4718c56c583Sjmcneill 	switch (di->index) {
4728c56c583Sjmcneill 	case 0: /* inputs.dac mixer value */
4738c56c583Sjmcneill 		di->mixer_class = 1;
4748c56c583Sjmcneill 		di->next = di->prev = AUDIO_MIXER_LAST;
4758c56c583Sjmcneill 		strcpy(di->label.name, AudioNdac);
4768c56c583Sjmcneill 		di->type = AUDIO_MIXER_VALUE;
4778c56c583Sjmcneill 		di->un.v.num_channels = 1;
4788c56c583Sjmcneill 		strcpy(di->un.v.units.name, AudioNvolume);
4798c56c583Sjmcneill 		return 0;
4808c56c583Sjmcneill 	case 1: /* outputs class */
4818c56c583Sjmcneill 		di->mixer_class = 1;
4828c56c583Sjmcneill 		di->next = di->prev = AUDIO_MIXER_LAST;
4838c56c583Sjmcneill 		strcpy(di->label.name, AudioCinputs);
4848c56c583Sjmcneill 		di->type = AUDIO_MIXER_CLASS;
4858c56c583Sjmcneill 		return 0;
4868c56c583Sjmcneill 	}
4878c56c583Sjmcneill 
488fddeb95fShamajima 	return ENXIO;
489fddeb95fShamajima }
490fddeb95fShamajima 
491fddeb95fShamajima int
vraiu_get_props(void * self)492fddeb95fShamajima vraiu_get_props(void *self)
493fddeb95fShamajima {
494fddeb95fShamajima 	DPRINTFN(3, ("vraiu_get_props\n"));
495fddeb95fShamajima 
496*df83eae3Sskrll 	return AUDIO_PROP_PLAYBACK;
497fddeb95fShamajima }
498fddeb95fShamajima 
4998a962f23Sjmcneill void
vraiu_get_locks(void * self,kmutex_t ** intr,kmutex_t ** thread)5008a962f23Sjmcneill vraiu_get_locks(void *self, kmutex_t **intr, kmutex_t **thread)
5018a962f23Sjmcneill {
5028a962f23Sjmcneill 	struct vraiu_softc *sc;
5038a962f23Sjmcneill 
5048a962f23Sjmcneill 	DPRINTFN(3, ("vraiu_get_locks\n"));
5058a962f23Sjmcneill 	sc = self;
5068a962f23Sjmcneill 
5078a962f23Sjmcneill 	*intr = &sc->sc_intr_lock;
5088a962f23Sjmcneill 	*thread = &sc->sc_lock;
5098a962f23Sjmcneill }
5108a962f23Sjmcneill 
511e622eac4Sisaki /* slinear16/mono -> ulinear10/mono with volume */
512fddeb95fShamajima static void
vraiu_slinear16_1(struct vraiu_softc * sc,u_short * dmap,void * p,int n)513fddeb95fShamajima vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
514fddeb95fShamajima {
51593293b9eSkent 	short *q;
516fddeb95fShamajima 
517fddeb95fShamajima 	DPRINTFN(3, ("vraiu_slinear16_1\n"));
51893293b9eSkent 	q = p;
519fddeb95fShamajima #ifdef DIAGNOSTIC
520fddeb95fShamajima 	if (n > AUDIO_BUF_SIZE) {
521fddeb95fShamajima 		printf("%s: output data too large (%d > %d)\n",
522cbab9cadSchs 		       device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE);
523fddeb95fShamajima 		n = AUDIO_BUF_SIZE;
524fddeb95fShamajima 	}
525fddeb95fShamajima #endif
526fddeb95fShamajima 	n /= 2;
527fddeb95fShamajima 	while (n--) {
528e622eac4Sisaki 		int i = *q++;
529e622eac4Sisaki 		i = i * sc->sc_volume / 255;
530fddeb95fShamajima 		*dmap++ = (i >> 6) + 0x200;
531fddeb95fShamajima 	}
532fddeb95fShamajima }
533