xref: /netbsd-src/sys/dev/acpi/wb_acpi.c (revision 569b81e6641694e02384b5616072019068b35f00)
1*569b81e6Sjmcneill /* $NetBSD: wb_acpi.c,v 1.7 2020/12/07 10:02:51 jmcneill Exp $ */
26c62f917Sjmcneill 
36c62f917Sjmcneill /*
46c62f917Sjmcneill  * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
56c62f917Sjmcneill  * All rights reserved.
66c62f917Sjmcneill  *
76c62f917Sjmcneill  * Redistribution and use in source and binary forms, with or without
86c62f917Sjmcneill  * modification, are permitted provided that the following conditions
96c62f917Sjmcneill  * are met:
106c62f917Sjmcneill  * 1. Redistributions of source code must retain the above copyright
116c62f917Sjmcneill  *    notice, this list of conditions and the following disclaimer.
126c62f917Sjmcneill  * 2. The name of the author may not be used to endorse or promote products
136c62f917Sjmcneill  *    derived from this software without specific prior written permission.
146c62f917Sjmcneill  *
156c62f917Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
166c62f917Sjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
176c62f917Sjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
186c62f917Sjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
196c62f917Sjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
206c62f917Sjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
216c62f917Sjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
226c62f917Sjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
236c62f917Sjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246c62f917Sjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256c62f917Sjmcneill  * SUCH DAMAGE.
266c62f917Sjmcneill  */
276c62f917Sjmcneill 
286c62f917Sjmcneill #include <sys/cdefs.h>
29*569b81e6Sjmcneill __KERNEL_RCSID(0, "$NetBSD: wb_acpi.c,v 1.7 2020/12/07 10:02:51 jmcneill Exp $");
306c62f917Sjmcneill 
316c62f917Sjmcneill #include <sys/param.h>
326c62f917Sjmcneill #include <sys/device.h>
335a425210Sjruoho #include <sys/systm.h>
346c62f917Sjmcneill 
3511d8465eSjmcneill #include <dev/acpi/acpireg.h>
366c62f917Sjmcneill #include <dev/acpi/acpivar.h>
378d11c112Sjmcneill #include <dev/acpi/acpi_intr.h>
386c62f917Sjmcneill 
396c62f917Sjmcneill #include <dev/ic/w83l518dvar.h>
406c62f917Sjmcneill #include <dev/ic/w83l518dreg.h>
416c62f917Sjmcneill 
425a425210Sjruoho #include <dev/isa/isadmavar.h>
435a425210Sjruoho 
445a425210Sjruoho #include <dev/sdmmc/sdmmcvar.h>
455a425210Sjruoho 
46e9887a18Sjmcneill #define _COMPONENT	ACPI_RESOURCE_COMPONENT
47e9887a18Sjmcneill ACPI_MODULE_NAME	("wb_acpi")
48e9887a18Sjmcneill 
496c62f917Sjmcneill static int	wb_acpi_match(device_t, cfdata_t, void *);
506c62f917Sjmcneill static void	wb_acpi_attach(device_t, device_t, void *);
516c62f917Sjmcneill static int	wb_acpi_detach(device_t, int);
5270496e9aSjmcneill static bool	wb_acpi_suspend(device_t, const pmf_qual_t *);
5370496e9aSjmcneill static bool	wb_acpi_resume(device_t, const pmf_qual_t *);
546c62f917Sjmcneill 
556c62f917Sjmcneill struct wb_acpi_softc {
566c62f917Sjmcneill 	struct wb_softc sc_wb;
576c62f917Sjmcneill 	isa_chipset_tag_t sc_ic;
586c62f917Sjmcneill 	void *sc_ih;
596c62f917Sjmcneill 	int sc_ioh_length;
6070496e9aSjmcneill 
6170496e9aSjmcneill 	ACPI_HANDLE sc_crs, sc_srs;
6270496e9aSjmcneill 	ACPI_BUFFER sc_crs_buffer;
636c62f917Sjmcneill };
646c62f917Sjmcneill 
656c62f917Sjmcneill CFATTACH_DECL_NEW(wb_acpi, sizeof(struct wb_acpi_softc),
666c62f917Sjmcneill     wb_acpi_match,
676c62f917Sjmcneill     wb_acpi_attach,
686c62f917Sjmcneill     wb_acpi_detach,
696c62f917Sjmcneill     NULL
706c62f917Sjmcneill );
716c62f917Sjmcneill 
726c62f917Sjmcneill static const char * const wb_acpi_ids[] = {
736c62f917Sjmcneill #if notyet
746c62f917Sjmcneill 	"WEC0515",	/* Memory Stick interface */
756c62f917Sjmcneill #endif
766c62f917Sjmcneill 	"WEC0517",	/* SD Memory Card interface */
776c62f917Sjmcneill 	NULL
786c62f917Sjmcneill };
796c62f917Sjmcneill 
806c62f917Sjmcneill static int
wb_acpi_match(device_t parent,cfdata_t match,void * opaque)816c62f917Sjmcneill wb_acpi_match(device_t parent, cfdata_t match, void *opaque)
826c62f917Sjmcneill {
836c62f917Sjmcneill 	struct acpi_attach_args *aa = opaque;
846c62f917Sjmcneill 
856c62f917Sjmcneill 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
866c62f917Sjmcneill 		return 0;
876c62f917Sjmcneill 
886c62f917Sjmcneill 	return acpi_match_hid(aa->aa_node->ad_devinfo, wb_acpi_ids);
896c62f917Sjmcneill }
906c62f917Sjmcneill 
916c62f917Sjmcneill static void
wb_acpi_attach(device_t parent,device_t self,void * opaque)926c62f917Sjmcneill wb_acpi_attach(device_t parent, device_t self, void *opaque)
936c62f917Sjmcneill {
946c62f917Sjmcneill 	struct wb_acpi_softc *sc = device_private(self);
956c62f917Sjmcneill 	struct acpi_attach_args *aa = opaque;
966c62f917Sjmcneill 	struct acpi_resources res;
976c62f917Sjmcneill 	struct acpi_io *io;
986c62f917Sjmcneill 	struct acpi_irq *irq;
996c62f917Sjmcneill 	bus_space_handle_t ioh;
1006c62f917Sjmcneill 	ACPI_STATUS rv;
1016c62f917Sjmcneill 
1026c62f917Sjmcneill 	sc->sc_ic = aa->aa_ic;
1036c62f917Sjmcneill 
1046c62f917Sjmcneill 	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
1056c62f917Sjmcneill 	    &res, &acpi_resource_parse_ops_default);
1066c62f917Sjmcneill 	if (ACPI_FAILURE(rv))
1076c62f917Sjmcneill 		return;
1086c62f917Sjmcneill 
10970496e9aSjmcneill 	AcpiGetHandle(aa->aa_node->ad_handle, "_CRS", &sc->sc_crs);
11070496e9aSjmcneill 	AcpiGetHandle(aa->aa_node->ad_handle, "_SRS", &sc->sc_srs);
11170496e9aSjmcneill 	if (sc->sc_crs && sc->sc_srs) {
11270496e9aSjmcneill 		sc->sc_crs_buffer.Pointer = NULL;
11370496e9aSjmcneill 		sc->sc_crs_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
11470496e9aSjmcneill 		rv = AcpiGetCurrentResources(sc->sc_crs, &sc->sc_crs_buffer);
11570496e9aSjmcneill 		if (ACPI_FAILURE(rv))
11670496e9aSjmcneill 			sc->sc_crs = sc->sc_srs = NULL;
11770496e9aSjmcneill 	}
11870496e9aSjmcneill 
1196c62f917Sjmcneill 	io = acpi_res_io(&res, 0);
1206c62f917Sjmcneill 	irq = acpi_res_irq(&res, 0);
1216c62f917Sjmcneill 	if (io == NULL || irq == NULL) {
1226c62f917Sjmcneill 		aprint_error_dev(self, "incomplete resources\n");
1236c62f917Sjmcneill 		goto cleanup;
1246c62f917Sjmcneill 	}
1256c62f917Sjmcneill 
1266c62f917Sjmcneill 	if (bus_space_map(aa->aa_iot, io->ar_base, io->ar_length, 0, &ioh)) {
1276c62f917Sjmcneill 		aprint_error_dev(self, "couldn't map registers\n");
1286c62f917Sjmcneill 		goto cleanup;
1296c62f917Sjmcneill 	}
1306c62f917Sjmcneill 	sc->sc_ioh_length = io->ar_length;
1316c62f917Sjmcneill 
132*569b81e6Sjmcneill 	sc->sc_ih = acpi_intr_establish(self,
133*569b81e6Sjmcneill 	    (uint64_t)(uintptr_t)aa->aa_node->ad_handle,
1348d11c112Sjmcneill 	    IPL_SDMMC, false, wb_intr, &sc->sc_wb, device_xname(self));
1356c62f917Sjmcneill 	if (sc->sc_ih == NULL) {
1366c62f917Sjmcneill 		aprint_error_dev(self,
1376c62f917Sjmcneill 		    "couldn't establish interrupt handler\n");
1386c62f917Sjmcneill 		goto cleanup;
1396c62f917Sjmcneill 	}
1406c62f917Sjmcneill 
1416c62f917Sjmcneill 	sc->sc_wb.wb_dev = self;
1426c62f917Sjmcneill 	sc->sc_wb.wb_type = WB_DEVNO_SD;
1436c62f917Sjmcneill 	sc->sc_wb.wb_iot = aa->aa_iot;
1446c62f917Sjmcneill 	sc->sc_wb.wb_ioh = ioh;
1456c62f917Sjmcneill 	sc->sc_wb.wb_irq = irq->ar_irq;
1466c62f917Sjmcneill 	sc->sc_wb.wb_base = io->ar_base;
1476c62f917Sjmcneill 	wb_attach(&sc->sc_wb);
1486c62f917Sjmcneill 
14970496e9aSjmcneill 	pmf_device_register(self, wb_acpi_suspend, wb_acpi_resume);
15070496e9aSjmcneill 
1516c62f917Sjmcneill cleanup:
1526c62f917Sjmcneill 	acpi_resource_cleanup(&res);
1536c62f917Sjmcneill }
1546c62f917Sjmcneill 
1556c62f917Sjmcneill static int
wb_acpi_detach(device_t self,int flags)1566c62f917Sjmcneill wb_acpi_detach(device_t self, int flags)
1576c62f917Sjmcneill {
1586c62f917Sjmcneill 	struct wb_acpi_softc *sc = device_private(self);
1596c62f917Sjmcneill 	int rv;
1606c62f917Sjmcneill 
16170496e9aSjmcneill 	pmf_device_deregister(self);
16270496e9aSjmcneill 
16370496e9aSjmcneill 	if (sc->sc_crs_buffer.Pointer)
16470496e9aSjmcneill 		ACPI_FREE(sc->sc_crs_buffer.Pointer);
16570496e9aSjmcneill 
1666c62f917Sjmcneill 	rv = wb_detach(&sc->sc_wb, flags);
1676c62f917Sjmcneill 	if (rv)
1686c62f917Sjmcneill 		return rv;
1696c62f917Sjmcneill 
1706c62f917Sjmcneill 	if (sc->sc_ih)
1718d11c112Sjmcneill 		acpi_intr_disestablish(sc->sc_ih);
1726c62f917Sjmcneill 
1736c62f917Sjmcneill 	if (sc->sc_ioh_length > 0)
1746c62f917Sjmcneill 		bus_space_unmap(sc->sc_wb.wb_iot, sc->sc_wb.wb_ioh,
1756c62f917Sjmcneill 		    sc->sc_ioh_length);
1766c62f917Sjmcneill 
1776c62f917Sjmcneill 	return 0;
1786c62f917Sjmcneill }
17970496e9aSjmcneill 
18070496e9aSjmcneill static bool
wb_acpi_suspend(device_t self,const pmf_qual_t * qual)18170496e9aSjmcneill wb_acpi_suspend(device_t self, const pmf_qual_t *qual)
18270496e9aSjmcneill {
18370496e9aSjmcneill 	struct wb_acpi_softc *sc = device_private(self);
18470496e9aSjmcneill 
18570496e9aSjmcneill 	return wb_suspend(&sc->sc_wb);
18670496e9aSjmcneill }
18770496e9aSjmcneill 
18870496e9aSjmcneill static bool
wb_acpi_resume(device_t self,const pmf_qual_t * qual)18970496e9aSjmcneill wb_acpi_resume(device_t self, const pmf_qual_t *qual)
19070496e9aSjmcneill {
19170496e9aSjmcneill 	struct wb_acpi_softc *sc = device_private(self);
19270496e9aSjmcneill 	ACPI_STATUS rv;
19370496e9aSjmcneill 
19470496e9aSjmcneill 	if (sc->sc_crs && sc->sc_srs) {
19570496e9aSjmcneill 		rv = AcpiSetCurrentResources(sc->sc_srs, &sc->sc_crs_buffer);
19670496e9aSjmcneill 		if (ACPI_FAILURE(rv))
19770496e9aSjmcneill 			printf("%s: _SRS failed: %s\n",
19870496e9aSjmcneill 			    device_xname(self), AcpiFormatException(rv));
19970496e9aSjmcneill 	}
20070496e9aSjmcneill 
20170496e9aSjmcneill 	return wb_resume(&sc->sc_wb);
20270496e9aSjmcneill }
203