1169695Skan/* $NetBSD: ym_acpi.c,v 1.16 2019/05/08 13:40:17 isaki Exp $ */
2169695Skan
3169695Skan/*
4169695Skan * Copyright (c) 2006 Jasper Wallace <jasper@pointless.net>
5169695Skan * All rights reserved.
6169695Skan *
7169695Skan * Copyright (c) 2002 Jared D. McNeill <jmcneill@invisible.ca>
8169695Skan * All rights reserved.
9169695Skan *
10169695Skan * Redistribution and use in source and binary forms, with or without
11169695Skan * modification, are permitted provided that the following conditions
12169695Skan * are met:
13169695Skan * 1. Redistributions of source code must retain the above copyright
14169695Skan *    notice, this list of conditions and the following disclaimer.
15169695Skan * 2. The name of the author may not be used to endorse or promote products
16169695Skan *    derived from this software without specific prior written permission.
17169695Skan *
18169695Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19169695Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20169695Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21169695Skan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22169695Skan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23169695Skan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24169695Skan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25169695Skan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26169695Skan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27169695Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28169695Skan * SUCH DAMAGE.
29169695Skan */
30169695Skan
31169695Skan#include <sys/cdefs.h>
32169695Skan__KERNEL_RCSID(0, "$NetBSD: ym_acpi.c,v 1.16 2019/05/08 13:40:17 isaki Exp $");
33169695Skan
34169695Skan#include <sys/param.h>
35169695Skan#include <sys/systm.h>
36169695Skan
37169695Skan#include <dev/acpi/acpivar.h>
38169695Skan
39169695Skan#include <dev/audio/audio_if.h>
40169695Skan
41169695Skan#include <dev/ic/ad1848reg.h>
42169695Skan#include <dev/ic/opl3sa3reg.h>
43169695Skan
44169695Skan#include <dev/isa/ad1848var.h>
45169695Skan#include <dev/isa/wssreg.h>
46169695Skan#include <dev/isa/ymvar.h>
47169695Skan
48169695Skan
49169695Skanstatic int	ym_acpi_match(device_t, cfdata_t, void *);
50169695Skanstatic void	ym_acpi_attach(device_t, device_t, void *);
51169695Skan
52169695SkanCFATTACH_DECL_NEW(ym_acpi, sizeof(struct ym_softc), ym_acpi_match,
53169695Skan    ym_acpi_attach, NULL, NULL);
54169695Skan
55169695Skan/*
56169695Skan * ym_acpi_match: autoconf(9) match routine
57169695Skan */
58169695Skanstatic int
59169695Skanym_acpi_match(device_t parent, cfdata_t match, void *aux)
60169695Skan{
61169695Skan	struct acpi_attach_args *aa = aux;
62169695Skan
63169695Skan	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
64169695Skan		return 0;
65169695Skan	if (!(aa->aa_node->ad_devinfo->Valid & ACPI_VALID_HID))
66169695Skan		return 0;
67169695Skan	if (!aa->aa_node->ad_devinfo->HardwareId.String)
68169695Skan		return 0;
69169695Skan	/* Yamaha OPL3-SA2 or OPL3-SA3 */
70169695Skan	if (strcmp("YMH0021", aa->aa_node->ad_devinfo->HardwareId.String))
71169695Skan		return 0;
72169695Skan
73169695Skan	return 1;
74169695Skan}
75169695Skan
76169695Skan/*
77169695Skan * ym_acpi_attach: autoconf(9) attach routine
78169695Skan */
79169695Skanstatic void
80169695Skanym_acpi_attach(device_t parent, device_t self, void *aux)
81169695Skan{
82169695Skan	struct ym_softc *sc = device_private(self);
83169695Skan	struct acpi_attach_args *aa = aux;
84169695Skan	struct acpi_resources res;
85169695Skan	struct acpi_io *sb_io, *codec_io, *opl_io, *control_io;
86169695Skan#if NMPU_YM > 0
87169695Skan	struct acpi_io *mpu_io;
88169695Skan#endif
89169695Skan	struct acpi_irq *irq;
90169695Skan	struct acpi_drq *playdrq, *recdrq;
91169695Skan	struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848;
92169695Skan	ACPI_STATUS rv;
93169695Skan
94169695Skan	ac->sc_dev = self;
95169695Skan	/* Parse our resources */
96169695Skan	rv = acpi_resource_parse(self,
97169695Skan	    aa->aa_node->ad_handle, "_CRS", &res,
98169695Skan	    &acpi_resource_parse_ops_default);
99169695Skan	if (ACPI_FAILURE(rv))
100169695Skan		return;
101169695Skan
102169695Skan	/*
103169695Skan	 * sc_sb_ioh	 @ 0
104169695Skan	 * sc_ioh	 @ 1
105169695Skan	 * sc_opl_ioh	 @ 2
106169695Skan	 * sc_mpu_ioh	 @ 3
107169695Skan	 * sc_controlioh @ 4
108169695Skan	 */
109169695Skan
110169695Skan	/* Find and map our i/o registers */
111169695Skan	sc->sc_iot = aa->aa_iot;
112169695Skan	sb_io	 = acpi_res_io(&res, 0);
113169695Skan	codec_io = acpi_res_io(&res, 1);
114169695Skan	opl_io	 = acpi_res_io(&res, 2);
115169695Skan#if NMPU_YM > 0
116169695Skan	mpu_io	 = acpi_res_io(&res, 3);
117169695Skan#endif
118169695Skan	control_io = acpi_res_io(&res, 4);
119169695Skan
120169695Skan	if (sb_io == NULL || codec_io == NULL || opl_io == NULL ||
121169695Skan#if NMPU_YM > 0
122169695Skan	    mpu_io == NULL ||
123169695Skan#endif
124169695Skan	    control_io == NULL) {
125169695Skan		aprint_error_dev(self,
126169695Skan		    "unable to find i/o registers resource\n");
127		goto out;
128	}
129	if (bus_space_map(sc->sc_iot, sb_io->ar_base, sb_io->ar_length,
130	    0, &sc->sc_sb_ioh) != 0) {
131		aprint_error_dev(self, "unable to map i/o registers (sb)\n");
132		goto out;
133	}
134	if (bus_space_map(sc->sc_iot, codec_io->ar_base, codec_io->ar_length,
135	    0, &sc->sc_ioh) != 0) {
136		aprint_error_dev(self, "unable to map i/o registers (codec)\n");
137		goto out;
138	}
139	if (bus_space_map(sc->sc_iot, opl_io->ar_base, opl_io->ar_length,
140	    0, &sc->sc_opl_ioh) != 0) {
141		aprint_error_dev(self, "unable to map i/o registers (opl)\n");
142		goto out;
143	}
144#if NMPU_YM > 0
145	if (bus_space_map(sc->sc_iot, mpu_io->ar_base, mpu_io->ar_length,
146	    0, &sc->sc_mpu_ioh) != 0) {
147		aprint_error_dev(self, "unable to map i/o registers (mpu)\n");
148		goto out;
149	}
150#endif
151	if (bus_space_map(sc->sc_iot, control_io->ar_base,
152	    control_io->ar_length, 0, &sc->sc_controlioh) != 0) {
153		aprint_error_dev(self,
154		    "unable to map i/o registers (control)\n");
155		goto out;
156	}
157
158	sc->sc_ic = aa->aa_ic;
159
160	/* Find our IRQ */
161	irq = acpi_res_irq(&res, 0);
162	if (irq == NULL) {
163		aprint_error_dev(self, "unable to find irq resource\n");
164		/* XXX bus_space_unmap */
165		goto out;
166	}
167	sc->ym_irq = irq->ar_irq;
168
169	/* Find our playback and record DRQs */
170	playdrq = acpi_res_drq(&res, 0);
171	recdrq = acpi_res_drq(&res, 1);
172	if (playdrq == NULL) {
173		aprint_error_dev(self, "unable to find drq resources\n");
174		/* XXX bus_space_unmap */
175		goto out;
176	}
177	if (recdrq == NULL) {
178		/* half-duplex mode */
179		sc->ym_recdrq = sc->ym_playdrq = playdrq->ar_drq;
180	} else {
181		sc->ym_playdrq = playdrq->ar_drq;
182		sc->ym_recdrq = recdrq->ar_drq;
183	}
184
185	ac->sc_iot = sc->sc_iot;
186	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, WSS_CODEC,
187	    AD1848_NPORT, &ac->sc_ioh)) {
188		aprint_error_dev(self, "bus_space_subregion failed\n");
189		/* XXX cleanup */
190		goto out;
191	}
192
193	aprint_normal_dev(self, "");
194
195	ac->mode = 2;
196	ac->MCE_bit = MODE_CHANGE_ENABLE;
197
198	sc->sc_ad1848.sc_ic = sc->sc_ic;
199
200	/* Attach our ym device */
201	ym_attach(sc);
202
203 out:
204	acpi_resource_cleanup(&res);
205}
206