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