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