1 1.30 isaki /* $NetBSD: audioamd.c,v 1.30 2020/09/12 05:19:16 isaki Exp $ */ 2 1.1 augustss /* NetBSD: am7930_sparc.c,v 1.44 1999/03/14 22:29:00 jonathan Exp */ 3 1.1 augustss 4 1.1 augustss /* 5 1.1 augustss * Copyright (c) 1995 Rolf Grossmann 6 1.1 augustss * All rights reserved. 7 1.1 augustss * 8 1.1 augustss * Redistribution and use in source and binary forms, with or without 9 1.1 augustss * modification, are permitted provided that the following conditions 10 1.1 augustss * are met: 11 1.1 augustss * 1. Redistributions of source code must retain the above copyright 12 1.1 augustss * notice, this list of conditions and the following disclaimer. 13 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 augustss * notice, this list of conditions and the following disclaimer in the 15 1.1 augustss * documentation and/or other materials provided with the distribution. 16 1.1 augustss * 3. All advertising materials mentioning features or use of this software 17 1.1 augustss * must display the following acknowledgement: 18 1.1 augustss * This product includes software developed by Rolf Grossmann. 19 1.1 augustss * 4. The name of the author may not be used to endorse or promote products 20 1.1 augustss * derived from this software without specific prior written permission 21 1.1 augustss * 22 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 1.1 augustss * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 1.1 augustss * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 1.1 augustss * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 1.1 augustss * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 1.1 augustss * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 1.1 augustss * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 1.1 augustss * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 1.1 augustss * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 1.1 augustss * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 augustss */ 33 1.17 lukem 34 1.17 lukem #include <sys/cdefs.h> 35 1.30 isaki __KERNEL_RCSID(0, "$NetBSD: audioamd.c,v 1.30 2020/09/12 05:19:16 isaki Exp $"); 36 1.1 augustss 37 1.1 augustss #include "audio.h" 38 1.1 augustss #if NAUDIO > 0 39 1.1 augustss 40 1.1 augustss #include <sys/param.h> 41 1.1 augustss #include <sys/systm.h> 42 1.1 augustss #include <sys/errno.h> 43 1.1 augustss #include <sys/device.h> 44 1.22 ad #include <sys/bus.h> 45 1.22 ad #include <sys/intr.h> 46 1.23 ad #include <sys/mutex.h> 47 1.1 augustss 48 1.1 augustss #include <machine/autoconf.h> 49 1.1 augustss 50 1.1 augustss #include <sys/audioio.h> 51 1.29 isaki #include <dev/audio/audio_if.h> 52 1.1 augustss 53 1.1 augustss #include <dev/ic/am7930reg.h> 54 1.1 augustss #include <dev/ic/am7930var.h> 55 1.1 augustss 56 1.1 augustss #define AUDIO_ROM_NAME "audio" 57 1.1 augustss 58 1.1 augustss struct audioamd_softc { 59 1.1 augustss struct am7930_softc sc_am7930; /* glue to MI code */ 60 1.1 augustss 61 1.1 augustss bus_space_tag_t sc_bt; /* bus cookie */ 62 1.1 augustss bus_space_handle_t sc_bh; /* device registers */ 63 1.1 augustss }; 64 1.1 augustss 65 1.24 tsutsui int audioamd_mainbus_match(device_t, cfdata_t, void *); 66 1.24 tsutsui void audioamd_mainbus_attach(device_t, device_t, void *); 67 1.24 tsutsui int audioamd_obio_match(device_t, cfdata_t, void *); 68 1.24 tsutsui void audioamd_obio_attach(device_t, device_t, void *); 69 1.24 tsutsui int audioamd_sbus_match(device_t, cfdata_t, void *); 70 1.24 tsutsui void audioamd_sbus_attach(device_t, device_t, void *); 71 1.20 kent void audioamd_attach(struct audioamd_softc *, int); 72 1.1 augustss 73 1.26 tsutsui CFATTACH_DECL_NEW(audioamd_mainbus, sizeof(struct audioamd_softc), 74 1.12 thorpej audioamd_mainbus_match, audioamd_mainbus_attach, NULL, NULL); 75 1.1 augustss 76 1.26 tsutsui CFATTACH_DECL_NEW(audioamd_obio, sizeof(struct audioamd_softc), 77 1.13 jdc audioamd_obio_match, audioamd_obio_attach, NULL, NULL); 78 1.13 jdc 79 1.26 tsutsui CFATTACH_DECL_NEW(audioamd_sbus, sizeof(struct audioamd_softc), 80 1.12 thorpej audioamd_sbus_match, audioamd_sbus_attach, NULL, NULL); 81 1.1 augustss 82 1.1 augustss /* 83 1.1 augustss * Define our interface into the am7930 MI driver. 84 1.1 augustss */ 85 1.1 augustss 86 1.30 isaki uint8_t audioamd_codec_dread(struct am7930_softc *, int); 87 1.30 isaki void audioamd_codec_dwrite(struct am7930_softc *, int, uint8_t); 88 1.1 augustss 89 1.1 augustss struct am7930_glue audioamd_glue = { 90 1.30 isaki audioamd_codec_dread, 91 1.30 isaki audioamd_codec_dwrite, 92 1.1 augustss }; 93 1.1 augustss 94 1.1 augustss /* 95 1.1 augustss * Define our interface to the higher level audio driver. 96 1.1 augustss */ 97 1.20 kent int audioamd_getdev(void *, struct audio_device *); 98 1.1 augustss 99 1.19 yamt const struct audio_hw_if sa_hw_if = { 100 1.29 isaki .query_format = am7930_query_format, 101 1.29 isaki .set_format = am7930_set_format, 102 1.28 isaki .commit_settings = am7930_commit_settings, 103 1.30 isaki .trigger_output = am7930_trigger_output, 104 1.30 isaki .trigger_input = am7930_trigger_input, 105 1.28 isaki .halt_output = am7930_halt_output, 106 1.28 isaki .halt_input = am7930_halt_input, 107 1.28 isaki .getdev = audioamd_getdev, 108 1.28 isaki .set_port = am7930_set_port, 109 1.28 isaki .get_port = am7930_get_port, 110 1.28 isaki .query_devinfo = am7930_query_devinfo, 111 1.28 isaki .get_props = am7930_get_props, 112 1.30 isaki .get_locks = am7930_get_locks, 113 1.1 augustss }; 114 1.1 augustss 115 1.1 augustss struct audio_device audioamd_device = { 116 1.1 augustss "am7930", 117 1.1 augustss "x", 118 1.1 augustss "audioamd" 119 1.1 augustss }; 120 1.1 augustss 121 1.1 augustss 122 1.1 augustss int 123 1.24 tsutsui audioamd_mainbus_match(device_t parent, cfdata_t cf, void *aux) 124 1.1 augustss { 125 1.20 kent struct mainbus_attach_args *ma; 126 1.1 augustss 127 1.20 kent ma = aux; 128 1.1 augustss if (CPU_ISSUN4) 129 1.20 kent return 0; 130 1.20 kent return strcmp(AUDIO_ROM_NAME, ma->ma_name) == 0; 131 1.1 augustss } 132 1.1 augustss 133 1.1 augustss int 134 1.24 tsutsui audioamd_obio_match(device_t parent, cfdata_t cf, void *aux) 135 1.13 jdc { 136 1.20 kent union obio_attach_args *uoba; 137 1.13 jdc 138 1.20 kent uoba = aux; 139 1.13 jdc if (uoba->uoba_isobio4 != 0) 140 1.20 kent return 0; 141 1.13 jdc 142 1.20 kent return strcmp("audio", uoba->uoba_sbus.sa_name) == 0; 143 1.13 jdc } 144 1.13 jdc 145 1.13 jdc int 146 1.24 tsutsui audioamd_sbus_match(device_t parent, cfdata_t cf, void *aux) 147 1.1 augustss { 148 1.20 kent struct sbus_attach_args *sa; 149 1.1 augustss 150 1.20 kent sa = aux; 151 1.20 kent return strcmp(AUDIO_ROM_NAME, sa->sa_name) == 0; 152 1.1 augustss } 153 1.1 augustss 154 1.1 augustss void 155 1.24 tsutsui audioamd_mainbus_attach(device_t parent, device_t self, void *aux) 156 1.1 augustss { 157 1.20 kent struct mainbus_attach_args *ma; 158 1.20 kent struct audioamd_softc *sc; 159 1.1 augustss bus_space_handle_t bh; 160 1.1 augustss 161 1.20 kent ma = aux; 162 1.24 tsutsui sc = device_private(self); 163 1.26 tsutsui sc->sc_am7930.sc_dev = self; 164 1.1 augustss sc->sc_bt = ma->ma_bustag; 165 1.1 augustss 166 1.8 pk if (bus_space_map( 167 1.1 augustss ma->ma_bustag, 168 1.1 augustss ma->ma_paddr, 169 1.2 mycroft AM7930_DREG_SIZE, 170 1.1 augustss BUS_SPACE_MAP_LINEAR, 171 1.1 augustss &bh) != 0) { 172 1.24 tsutsui printf("%s: cannot map registers\n", device_xname(self)); 173 1.1 augustss return; 174 1.1 augustss } 175 1.1 augustss sc->sc_bh = bh; 176 1.1 augustss audioamd_attach(sc, ma->ma_pri); 177 1.1 augustss } 178 1.1 augustss 179 1.13 jdc void 180 1.24 tsutsui audioamd_obio_attach(device_t parent, device_t self, void *aux) 181 1.20 kent { 182 1.20 kent union obio_attach_args *uoba; 183 1.20 kent struct sbus_attach_args *sa; 184 1.20 kent struct audioamd_softc *sc; 185 1.13 jdc bus_space_handle_t bh; 186 1.13 jdc 187 1.20 kent uoba = aux; 188 1.20 kent sa = &uoba->uoba_sbus; 189 1.24 tsutsui sc = device_private(self); 190 1.26 tsutsui sc->sc_am7930.sc_dev = self; 191 1.13 jdc sc->sc_bt = sa->sa_bustag; 192 1.13 jdc 193 1.13 jdc if (sbus_bus_map(sa->sa_bustag, 194 1.13 jdc sa->sa_slot, sa->sa_offset, 195 1.13 jdc AM7930_DREG_SIZE, 196 1.13 jdc 0, &bh) != 0) { 197 1.24 tsutsui printf("%s: cannot map registers\n", device_xname(self)); 198 1.13 jdc return; 199 1.13 jdc } 200 1.13 jdc sc->sc_bh = bh; 201 1.13 jdc audioamd_attach(sc, sa->sa_pri); 202 1.13 jdc } 203 1.1 augustss 204 1.1 augustss void 205 1.24 tsutsui audioamd_sbus_attach(device_t parent, device_t self, void *aux) 206 1.1 augustss { 207 1.20 kent struct sbus_attach_args *sa; 208 1.20 kent struct audioamd_softc *sc; 209 1.1 augustss bus_space_handle_t bh; 210 1.1 augustss 211 1.20 kent sa = aux; 212 1.24 tsutsui sc = device_private(self); 213 1.26 tsutsui sc->sc_am7930.sc_dev = self; 214 1.1 augustss sc->sc_bt = sa->sa_bustag; 215 1.1 augustss 216 1.8 pk if (sbus_bus_map(sa->sa_bustag, 217 1.8 pk sa->sa_slot, sa->sa_offset, 218 1.8 pk AM7930_DREG_SIZE, 219 1.8 pk 0, &bh) != 0) { 220 1.24 tsutsui printf("%s: cannot map registers\n", device_xname(self)); 221 1.1 augustss return; 222 1.1 augustss } 223 1.1 augustss sc->sc_bh = bh; 224 1.1 augustss audioamd_attach(sc, sa->sa_pri); 225 1.1 augustss } 226 1.1 augustss 227 1.1 augustss void 228 1.20 kent audioamd_attach(struct audioamd_softc *sc, int pri) 229 1.1 augustss { 230 1.30 isaki struct am7930_softc *amsc = &sc->sc_am7930; 231 1.24 tsutsui device_t self; 232 1.1 augustss 233 1.1 augustss /* 234 1.1 augustss * Set up glue for MI code early; we use some of it here. 235 1.1 augustss */ 236 1.30 isaki amsc->sc_glue = &audioamd_glue; 237 1.30 isaki am7930_init(amsc, AUDIOAMD_POLL_MODE); 238 1.15 pk 239 1.23 ad (void)bus_intr_establish2(sc->sc_bt, pri, IPL_HIGH, 240 1.30 isaki am7930_hwintr, sc, NULL); 241 1.14 pk 242 1.30 isaki printf("\n"); 243 1.1 augustss 244 1.30 isaki self = amsc->sc_dev; 245 1.30 isaki evcnt_attach_dynamic(&amsc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 246 1.24 tsutsui device_xname(self), "intr"); 247 1.1 augustss 248 1.24 tsutsui audio_attach_mi(&sa_hw_if, sc, self); 249 1.1 augustss } 250 1.1 augustss 251 1.1 augustss 252 1.1 augustss /* direct read */ 253 1.20 kent uint8_t 254 1.30 isaki audioamd_codec_dread(struct am7930_softc *amsc, int reg) 255 1.2 mycroft { 256 1.30 isaki struct audioamd_softc *sc = (struct audioamd_softc *)amsc; 257 1.20 kent 258 1.20 kent return bus_space_read_1(sc->sc_bt, sc->sc_bh, reg); 259 1.2 mycroft } 260 1.2 mycroft 261 1.2 mycroft /* direct write */ 262 1.2 mycroft void 263 1.30 isaki audioamd_codec_dwrite(struct am7930_softc *amsc, int reg, uint8_t val) 264 1.1 augustss { 265 1.30 isaki struct audioamd_softc *sc = (struct audioamd_softc *)amsc; 266 1.20 kent 267 1.2 mycroft bus_space_write_1(sc->sc_bt, sc->sc_bh, reg, val); 268 1.2 mycroft } 269 1.2 mycroft 270 1.2 mycroft int 271 1.20 kent audioamd_getdev(void *addr, struct audio_device *retp) 272 1.2 mycroft { 273 1.2 mycroft 274 1.2 mycroft *retp = audioamd_device; 275 1.20 kent return 0; 276 1.1 augustss } 277 1.1 augustss 278 1.1 augustss #endif /* NAUDIO > 0 */ 279