xref: /netbsd-src/sys/arch/sparc/dev/audioamd.c (revision 08004a7e10cfd628d4ced7e33ae51167467d34a1)
1*08004a7eSisaki /*	$NetBSD: audioamd.c,v 1.30 2020/09/12 05:19:16 isaki Exp $	*/
2361f2141Saugustss /*	NetBSD: am7930_sparc.c,v 1.44 1999/03/14 22:29:00 jonathan Exp 	*/
3361f2141Saugustss 
4361f2141Saugustss /*
5361f2141Saugustss  * Copyright (c) 1995 Rolf Grossmann
6361f2141Saugustss  * All rights reserved.
7361f2141Saugustss  *
8361f2141Saugustss  * Redistribution and use in source and binary forms, with or without
9361f2141Saugustss  * modification, are permitted provided that the following conditions
10361f2141Saugustss  * are met:
11361f2141Saugustss  * 1. Redistributions of source code must retain the above copyright
12361f2141Saugustss  *    notice, this list of conditions and the following disclaimer.
13361f2141Saugustss  * 2. Redistributions in binary form must reproduce the above copyright
14361f2141Saugustss  *    notice, this list of conditions and the following disclaimer in the
15361f2141Saugustss  *    documentation and/or other materials provided with the distribution.
16361f2141Saugustss  * 3. All advertising materials mentioning features or use of this software
17361f2141Saugustss  *    must display the following acknowledgement:
18361f2141Saugustss  *      This product includes software developed by Rolf Grossmann.
19361f2141Saugustss  * 4. The name of the author may not be used to endorse or promote products
20361f2141Saugustss  *    derived from this software without specific prior written permission
21361f2141Saugustss  *
22361f2141Saugustss  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23361f2141Saugustss  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24361f2141Saugustss  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25361f2141Saugustss  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26361f2141Saugustss  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27361f2141Saugustss  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28361f2141Saugustss  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29361f2141Saugustss  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30361f2141Saugustss  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31361f2141Saugustss  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32361f2141Saugustss  */
33361f2141Saugustss 
34a4183603Slukem #include <sys/cdefs.h>
35*08004a7eSisaki __KERNEL_RCSID(0, "$NetBSD: audioamd.c,v 1.30 2020/09/12 05:19:16 isaki Exp $");
36a4183603Slukem 
37361f2141Saugustss #include "audio.h"
38361f2141Saugustss #if NAUDIO > 0
39361f2141Saugustss 
40361f2141Saugustss #include <sys/param.h>
41361f2141Saugustss #include <sys/systm.h>
42361f2141Saugustss #include <sys/errno.h>
43361f2141Saugustss #include <sys/device.h>
4499801e92Sad #include <sys/bus.h>
4599801e92Sad #include <sys/intr.h>
464b293a84Sad #include <sys/mutex.h>
47361f2141Saugustss 
48361f2141Saugustss #include <machine/autoconf.h>
49361f2141Saugustss 
50361f2141Saugustss #include <sys/audioio.h>
51e622eac4Sisaki #include <dev/audio/audio_if.h>
52361f2141Saugustss 
53361f2141Saugustss #include <dev/ic/am7930reg.h>
54361f2141Saugustss #include <dev/ic/am7930var.h>
55361f2141Saugustss 
56361f2141Saugustss #define AUDIO_ROM_NAME "audio"
57361f2141Saugustss 
58361f2141Saugustss struct audioamd_softc {
59361f2141Saugustss 	struct am7930_softc sc_am7930;	/* glue to MI code */
60361f2141Saugustss 
61361f2141Saugustss 	bus_space_tag_t sc_bt;		/* bus cookie */
62361f2141Saugustss 	bus_space_handle_t sc_bh;	/* device registers */
63361f2141Saugustss };
64361f2141Saugustss 
6541559777Stsutsui int	audioamd_mainbus_match(device_t, cfdata_t, void *);
6641559777Stsutsui void	audioamd_mainbus_attach(device_t, device_t, void *);
6741559777Stsutsui int	audioamd_obio_match(device_t, cfdata_t, void *);
6841559777Stsutsui void	audioamd_obio_attach(device_t, device_t, void *);
6941559777Stsutsui int	audioamd_sbus_match(device_t, cfdata_t, void *);
7041559777Stsutsui void	audioamd_sbus_attach(device_t, device_t, void *);
7193293b9eSkent void	audioamd_attach(struct audioamd_softc *, int);
72361f2141Saugustss 
73595cbc6aStsutsui CFATTACH_DECL_NEW(audioamd_mainbus, sizeof(struct audioamd_softc),
744bf871a7Sthorpej     audioamd_mainbus_match, audioamd_mainbus_attach, NULL, NULL);
75361f2141Saugustss 
76595cbc6aStsutsui CFATTACH_DECL_NEW(audioamd_obio, sizeof(struct audioamd_softc),
77d1f466e6Sjdc     audioamd_obio_match, audioamd_obio_attach, NULL, NULL);
78d1f466e6Sjdc 
79595cbc6aStsutsui CFATTACH_DECL_NEW(audioamd_sbus, sizeof(struct audioamd_softc),
804bf871a7Sthorpej     audioamd_sbus_match, audioamd_sbus_attach, NULL, NULL);
81361f2141Saugustss 
82361f2141Saugustss /*
83361f2141Saugustss  * Define our interface into the am7930 MI driver.
84361f2141Saugustss  */
85361f2141Saugustss 
86*08004a7eSisaki uint8_t	audioamd_codec_dread(struct am7930_softc *, int);
87*08004a7eSisaki void	audioamd_codec_dwrite(struct am7930_softc *, int, uint8_t);
88361f2141Saugustss 
89361f2141Saugustss struct am7930_glue audioamd_glue = {
90*08004a7eSisaki 	audioamd_codec_dread,
91*08004a7eSisaki 	audioamd_codec_dwrite,
92361f2141Saugustss };
93361f2141Saugustss 
94361f2141Saugustss /*
95361f2141Saugustss  * Define our interface to the higher level audio driver.
96361f2141Saugustss  */
9793293b9eSkent int	audioamd_getdev(void *, struct audio_device *);
98361f2141Saugustss 
9918f717bbSyamt const struct audio_hw_if sa_hw_if = {
100e622eac4Sisaki 	.query_format		= am7930_query_format,
101e622eac4Sisaki 	.set_format		= am7930_set_format,
1026291b134Sisaki 	.commit_settings	= am7930_commit_settings,
103*08004a7eSisaki 	.trigger_output		= am7930_trigger_output,
104*08004a7eSisaki 	.trigger_input		= am7930_trigger_input,
1056291b134Sisaki 	.halt_output		= am7930_halt_output,
1066291b134Sisaki 	.halt_input		= am7930_halt_input,
1076291b134Sisaki 	.getdev			= audioamd_getdev,
1086291b134Sisaki 	.set_port		= am7930_set_port,
1096291b134Sisaki 	.get_port		= am7930_get_port,
1106291b134Sisaki 	.query_devinfo		= am7930_query_devinfo,
1116291b134Sisaki 	.get_props		= am7930_get_props,
112*08004a7eSisaki 	.get_locks		= am7930_get_locks,
113361f2141Saugustss };
114361f2141Saugustss 
115361f2141Saugustss struct audio_device audioamd_device = {
116361f2141Saugustss 	"am7930",
117361f2141Saugustss 	"x",
118361f2141Saugustss 	"audioamd"
119361f2141Saugustss };
120361f2141Saugustss 
121361f2141Saugustss 
122361f2141Saugustss int
audioamd_mainbus_match(device_t parent,cfdata_t cf,void * aux)12341559777Stsutsui audioamd_mainbus_match(device_t parent, cfdata_t cf, void *aux)
124361f2141Saugustss {
12593293b9eSkent 	struct mainbus_attach_args *ma;
126361f2141Saugustss 
12793293b9eSkent 	ma = aux;
128361f2141Saugustss 	if (CPU_ISSUN4)
12993293b9eSkent 		return 0;
13093293b9eSkent 	return strcmp(AUDIO_ROM_NAME, ma->ma_name) == 0;
131361f2141Saugustss }
132361f2141Saugustss 
133361f2141Saugustss int
audioamd_obio_match(device_t parent,cfdata_t cf,void * aux)13441559777Stsutsui audioamd_obio_match(device_t parent, cfdata_t cf, void *aux)
135d1f466e6Sjdc {
13693293b9eSkent 	union obio_attach_args *uoba;
137d1f466e6Sjdc 
13893293b9eSkent 	uoba = aux;
139d1f466e6Sjdc 	if (uoba->uoba_isobio4 != 0)
14093293b9eSkent 		return 0;
141d1f466e6Sjdc 
14293293b9eSkent 	return strcmp("audio", uoba->uoba_sbus.sa_name) == 0;
143d1f466e6Sjdc }
144d1f466e6Sjdc 
145d1f466e6Sjdc int
audioamd_sbus_match(device_t parent,cfdata_t cf,void * aux)14641559777Stsutsui audioamd_sbus_match(device_t parent, cfdata_t cf, void *aux)
147361f2141Saugustss {
14893293b9eSkent 	struct sbus_attach_args *sa;
149361f2141Saugustss 
15093293b9eSkent 	sa = aux;
15193293b9eSkent 	return strcmp(AUDIO_ROM_NAME, sa->sa_name) == 0;
152361f2141Saugustss }
153361f2141Saugustss 
154361f2141Saugustss void
audioamd_mainbus_attach(device_t parent,device_t self,void * aux)15541559777Stsutsui audioamd_mainbus_attach(device_t parent, device_t self, void *aux)
156361f2141Saugustss {
15793293b9eSkent 	struct mainbus_attach_args *ma;
15893293b9eSkent 	struct audioamd_softc *sc;
159361f2141Saugustss 	bus_space_handle_t bh;
160361f2141Saugustss 
16193293b9eSkent 	ma = aux;
16241559777Stsutsui 	sc = device_private(self);
163595cbc6aStsutsui 	sc->sc_am7930.sc_dev = self;
164361f2141Saugustss 	sc->sc_bt = ma->ma_bustag;
165361f2141Saugustss 
1667e8becd6Spk 	if (bus_space_map(
167361f2141Saugustss 			ma->ma_bustag,
168361f2141Saugustss 			ma->ma_paddr,
169f5bd37beSmycroft 			AM7930_DREG_SIZE,
170361f2141Saugustss 			BUS_SPACE_MAP_LINEAR,
171361f2141Saugustss 			&bh) != 0) {
17241559777Stsutsui 		printf("%s: cannot map registers\n", device_xname(self));
173361f2141Saugustss 		return;
174361f2141Saugustss 	}
175361f2141Saugustss 	sc->sc_bh = bh;
176361f2141Saugustss 	audioamd_attach(sc, ma->ma_pri);
177361f2141Saugustss }
178361f2141Saugustss 
179d1f466e6Sjdc void
audioamd_obio_attach(device_t parent,device_t self,void * aux)18041559777Stsutsui audioamd_obio_attach(device_t parent, device_t self, void *aux)
181d1f466e6Sjdc {
18293293b9eSkent 	union obio_attach_args *uoba;
18393293b9eSkent 	struct sbus_attach_args *sa;
184361f2141Saugustss 	struct audioamd_softc *sc;
18593293b9eSkent 	bus_space_handle_t bh;
18693293b9eSkent 
18793293b9eSkent 	uoba = aux;
18893293b9eSkent 	sa = &uoba->uoba_sbus;
18941559777Stsutsui 	sc = device_private(self);
190595cbc6aStsutsui 	sc->sc_am7930.sc_dev = self;
19193293b9eSkent 	sc->sc_bt = sa->sa_bustag;
19293293b9eSkent 
19393293b9eSkent 	if (sbus_bus_map(sa->sa_bustag,
19493293b9eSkent 			 sa->sa_slot, sa->sa_offset,
19593293b9eSkent 			 AM7930_DREG_SIZE,
19693293b9eSkent 			 0, &bh) != 0) {
19741559777Stsutsui 		printf("%s: cannot map registers\n", device_xname(self));
19893293b9eSkent 		return;
19993293b9eSkent 	}
20093293b9eSkent 	sc->sc_bh = bh;
20193293b9eSkent 	audioamd_attach(sc, sa->sa_pri);
20293293b9eSkent }
20393293b9eSkent 
20493293b9eSkent void
audioamd_sbus_attach(device_t parent,device_t self,void * aux)20541559777Stsutsui audioamd_sbus_attach(device_t parent, device_t self, void *aux)
20693293b9eSkent {
20793293b9eSkent 	struct sbus_attach_args *sa;
20893293b9eSkent 	struct audioamd_softc *sc;
20993293b9eSkent 	bus_space_handle_t bh;
21093293b9eSkent 
21193293b9eSkent 	sa = aux;
21241559777Stsutsui 	sc = device_private(self);
213595cbc6aStsutsui 	sc->sc_am7930.sc_dev = self;
21493293b9eSkent 	sc->sc_bt = sa->sa_bustag;
21593293b9eSkent 
21693293b9eSkent 	if (sbus_bus_map(sa->sa_bustag,
21793293b9eSkent 			 sa->sa_slot, sa->sa_offset,
21893293b9eSkent 			 AM7930_DREG_SIZE,
21993293b9eSkent 			 0, &bh) != 0) {
22041559777Stsutsui 		printf("%s: cannot map registers\n", device_xname(self));
22193293b9eSkent 		return;
22293293b9eSkent 	}
22393293b9eSkent 	sc->sc_bh = bh;
22493293b9eSkent 	audioamd_attach(sc, sa->sa_pri);
22593293b9eSkent }
22693293b9eSkent 
22793293b9eSkent void
audioamd_attach(struct audioamd_softc * sc,int pri)22893293b9eSkent audioamd_attach(struct audioamd_softc *sc, int pri)
229361f2141Saugustss {
230*08004a7eSisaki 	struct am7930_softc *amsc = &sc->sc_am7930;
23141559777Stsutsui 	device_t self;
232361f2141Saugustss 
233361f2141Saugustss 	/*
234361f2141Saugustss 	 * Set up glue for MI code early; we use some of it here.
235361f2141Saugustss 	 */
236*08004a7eSisaki 	amsc->sc_glue = &audioamd_glue;
237*08004a7eSisaki 	am7930_init(amsc, AUDIOAMD_POLL_MODE);
238361f2141Saugustss 
2394b293a84Sad 	(void)bus_intr_establish2(sc->sc_bt, pri, IPL_HIGH,
240*08004a7eSisaki 				  am7930_hwintr, sc, NULL);
241c822c6bdSpk 
242*08004a7eSisaki 	printf("\n");
243c822c6bdSpk 
244*08004a7eSisaki 	self = amsc->sc_dev;
245*08004a7eSisaki 	evcnt_attach_dynamic(&amsc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
24641559777Stsutsui 	    device_xname(self), "intr");
247361f2141Saugustss 
24841559777Stsutsui 	audio_attach_mi(&sa_hw_if, sc, self);
249361f2141Saugustss }
250361f2141Saugustss 
251361f2141Saugustss 
252f5bd37beSmycroft /* direct read */
25393293b9eSkent uint8_t
audioamd_codec_dread(struct am7930_softc * amsc,int reg)254*08004a7eSisaki audioamd_codec_dread(struct am7930_softc *amsc, int reg)
255f5bd37beSmycroft {
256*08004a7eSisaki 	struct audioamd_softc *sc = (struct audioamd_softc *)amsc;
25793293b9eSkent 
25893293b9eSkent 	return bus_space_read_1(sc->sc_bt, sc->sc_bh, reg);
259361f2141Saugustss }
260361f2141Saugustss 
261361f2141Saugustss /* direct write */
262361f2141Saugustss void
audioamd_codec_dwrite(struct am7930_softc * amsc,int reg,uint8_t val)263*08004a7eSisaki audioamd_codec_dwrite(struct am7930_softc *amsc, int reg, uint8_t val)
264361f2141Saugustss {
265*08004a7eSisaki 	struct audioamd_softc *sc = (struct audioamd_softc *)amsc;
26693293b9eSkent 
267f5bd37beSmycroft 	bus_space_write_1(sc->sc_bt, sc->sc_bh, reg, val);
268361f2141Saugustss }
269361f2141Saugustss 
270f5bd37beSmycroft int
audioamd_getdev(void * addr,struct audio_device * retp)27193293b9eSkent audioamd_getdev(void *addr, struct audio_device *retp)
272361f2141Saugustss {
273f5bd37beSmycroft 
274f5bd37beSmycroft 	*retp = audioamd_device;
27593293b9eSkent 	return 0;
276361f2141Saugustss }
277361f2141Saugustss 
278361f2141Saugustss #endif /* NAUDIO > 0 */
279