apple_smc_acpi.c revision 1.2
1/*	$NetBSD: apple_smc_acpi.c,v 1.2 2014/04/01 17:48:39 riastradh Exp $	*/
2
3/*
4 * Apple System Management Controller: ACPI Attachment
5 */
6
7/*-
8 * Copyright (c) 2013 Taylor R. Campbell
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: apple_smc_acpi.c,v 1.2 2014/04/01 17:48:39 riastradh Exp $");
35
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/module.h>
40
41#include <dev/acpi/acpireg.h>
42#include <dev/acpi/acpivar.h>
43
44#include <dev/ic/apple_smcreg.h>
45#include <dev/ic/apple_smcvar.h>
46
47#define _COMPONENT		ACPI_RESOURCE_COMPONENT
48ACPI_MODULE_NAME		("apple_smc_acpi")
49
50struct apple_smc_acpi_softc {
51	struct apple_smc_tag	sc_smc;
52};
53
54static int	apple_smc_acpi_match(device_t, cfdata_t, void *);
55static void	apple_smc_acpi_attach(device_t, device_t, void *);
56static int	apple_smc_acpi_detach(device_t, int);
57static int	apple_smc_acpi_rescan(device_t, const char *, const int *);
58static void	apple_smc_acpi_child_detached(device_t, device_t);
59
60CFATTACH_DECL2_NEW(apple_smc_acpi, sizeof(struct apple_smc_acpi_softc),
61    apple_smc_acpi_match,
62    apple_smc_acpi_attach,
63    apple_smc_acpi_detach,
64    NULL /* activate */,
65    apple_smc_acpi_rescan,
66    apple_smc_acpi_child_detached);
67
68static const char *const apple_smc_ids[] = {
69	"APP0001",
70	NULL
71};
72
73static int
74apple_smc_acpi_match(device_t parent, cfdata_t match, void *aux)
75{
76	struct acpi_attach_args *aa = aux;
77
78	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
79		return 0;
80
81	if (!acpi_match_hid(aa->aa_node->ad_devinfo, apple_smc_ids))
82		return 0;
83
84	return 1;
85}
86
87static void
88apple_smc_acpi_attach(device_t parent, device_t self, void *aux)
89{
90	struct apple_smc_acpi_softc *sc = device_private(self);
91	struct apple_smc_tag *smc = &sc->sc_smc;
92	struct acpi_attach_args *aa = aux;
93	struct acpi_resources res;
94	struct acpi_io *io;
95	int rv;
96
97	smc->smc_dev = self;
98
99	aprint_normal("\n");
100	aprint_naive("\n");
101
102	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
103	    &res, &acpi_resource_parse_ops_default);
104	if (ACPI_FAILURE(rv)) {
105		aprint_error_dev(self, "couldn't parse SMC resources: %s\n",
106		    AcpiFormatException(rv));
107		goto out0;
108	}
109
110	io = acpi_res_io(&res, 0);
111	if (io == NULL) {
112		aprint_error_dev(self, "no I/O resource\n");
113		goto out1;
114	}
115
116	if (io->ar_length < APPLE_SMC_REGSIZE) {
117		aprint_error_dev(self, "I/O resources too small: %"PRId32"\n",
118		    io->ar_length);
119		goto out1;
120	}
121
122	if (bus_space_map(aa->aa_iot, io->ar_base, io->ar_length, 0,
123		&smc->smc_bsh) != 0) {
124		aprint_error_dev(self, "unable to map I/O registers\n");
125		goto out1;
126	}
127
128	smc->smc_bst = aa->aa_iot;
129	smc->smc_size = io->ar_length;
130
131	apple_smc_attach(smc);
132
133out1:	acpi_resource_cleanup(&res);
134out0:	return;
135}
136
137static int
138apple_smc_acpi_detach(device_t self, int flags)
139{
140	struct apple_smc_acpi_softc *sc = device_private(self);
141	struct apple_smc_tag *smc = &sc->sc_smc;
142	int error;
143
144	if (smc->smc_size != 0) {
145		error = apple_smc_detach(smc, flags);
146		if (error)
147			return error;
148
149		bus_space_unmap(smc->smc_bst, smc->smc_bsh, smc->smc_size);
150		smc->smc_size = 0;
151	}
152
153	return 0;
154}
155
156static int
157apple_smc_acpi_rescan(device_t self, const char *ifattr, const int *locs)
158{
159	struct apple_smc_acpi_softc *const sc = device_private(self);
160
161	return apple_smc_rescan(&sc->sc_smc, ifattr, locs);
162}
163
164static void
165apple_smc_acpi_child_detached(device_t self, device_t child)
166{
167	struct apple_smc_acpi_softc *const sc = device_private(self);
168
169	apple_smc_child_detached(&sc->sc_smc, child);
170}
171
172MODULE(MODULE_CLASS_DRIVER, apple_smc_acpi, "apple_smc");
173
174#ifdef _MODULE
175#include "ioconf.c"
176#endif
177
178static int
179apple_smc_acpi_modcmd(modcmd_t cmd, void *arg __unused)
180{
181	int error;
182
183	switch (cmd) {
184	case MODULE_CMD_INIT:
185#ifdef _MODULE
186		error = config_init_component(cfdriver_ioconf_apple_smc_acpi,
187		    cfattach_ioconf_apple_smc_acpi,
188		    cfdata_ioconf_apple_smc_acpi);
189		if (error)
190			return error;
191#endif
192		return 0;
193
194	case MODULE_CMD_FINI:
195#ifdef _MODULE
196		error = config_fini_component(cfdriver_ioconf_apple_smc_acpi,
197		    cfattach_ioconf_apple_smc_acpi,
198		    cfdata_ioconf_apple_smc_acpi);
199		if (error)
200			return error;
201#endif
202		return 0;
203
204	default:
205		return ENOTTY;
206	}
207}
208