1*64fbda90SVal Packett /*-
2*64fbda90SVal Packett * SPDX-License-Identifier: BSD-2-Clause
3*64fbda90SVal Packett *
4*64fbda90SVal Packett * Copyright (c) 2021-2023 Val Packett <val@packett.cool>
5*64fbda90SVal Packett * Copyright (c) 2023 Vladimir Kondratyev <wulf@FreeBSD.org>
6*64fbda90SVal Packett *
7*64fbda90SVal Packett * Redistribution and use in source and binary forms, with or without
8*64fbda90SVal Packett * modification, are permitted provided that the following conditions
9*64fbda90SVal Packett * are met:
10*64fbda90SVal Packett * 1. Redistributions of source code must retain the above copyright
11*64fbda90SVal Packett * notice, this list of conditions and the following disclaimer.
12*64fbda90SVal Packett * 2. Redistributions in binary form must reproduce the above copyright
13*64fbda90SVal Packett * notice, this list of conditions and the following disclaimer in the
14*64fbda90SVal Packett * documentation and/or other materials provided with the distribution.
15*64fbda90SVal Packett *
16*64fbda90SVal Packett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*64fbda90SVal Packett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*64fbda90SVal Packett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*64fbda90SVal Packett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*64fbda90SVal Packett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*64fbda90SVal Packett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*64fbda90SVal Packett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*64fbda90SVal Packett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*64fbda90SVal Packett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*64fbda90SVal Packett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*64fbda90SVal Packett * SUCH DAMAGE.
27*64fbda90SVal Packett */
28*64fbda90SVal Packett
29*64fbda90SVal Packett #include "opt_acpi.h"
30*64fbda90SVal Packett #include "opt_hid.h"
31*64fbda90SVal Packett
32*64fbda90SVal Packett #include <sys/param.h>
33*64fbda90SVal Packett #include <sys/bus.h>
34*64fbda90SVal Packett #include <sys/kernel.h>
35*64fbda90SVal Packett #include <sys/malloc.h>
36*64fbda90SVal Packett #include <sys/mutex.h>
37*64fbda90SVal Packett #include <sys/module.h>
38*64fbda90SVal Packett #include <sys/rman.h>
39*64fbda90SVal Packett #include <sys/sx.h>
40*64fbda90SVal Packett #include <sys/taskqueue.h>
41*64fbda90SVal Packett
42*64fbda90SVal Packett #include <contrib/dev/acpica/include/acpi.h>
43*64fbda90SVal Packett #include <contrib/dev/acpica/include/accommon.h>
44*64fbda90SVal Packett #include <contrib/dev/acpica/include/acevents.h>
45*64fbda90SVal Packett #include <dev/acpica/acpivar.h>
46*64fbda90SVal Packett #include <dev/acpica/acpiio.h>
47*64fbda90SVal Packett
48*64fbda90SVal Packett #include <dev/backlight/backlight.h>
49*64fbda90SVal Packett
50*64fbda90SVal Packett #include <dev/evdev/input.h>
51*64fbda90SVal Packett
52*64fbda90SVal Packett #define HID_DEBUG_VAR atopcase_debug
53*64fbda90SVal Packett #include <dev/hid/hid.h>
54*64fbda90SVal Packett #include <dev/hid/hidquirk.h>
55*64fbda90SVal Packett
56*64fbda90SVal Packett #include <dev/spibus/spi.h>
57*64fbda90SVal Packett #include <dev/spibus/spibusvar.h>
58*64fbda90SVal Packett
59*64fbda90SVal Packett #include "backlight_if.h"
60*64fbda90SVal Packett #include "hid_if.h"
61*64fbda90SVal Packett
62*64fbda90SVal Packett #include "atopcase_reg.h"
63*64fbda90SVal Packett #include "atopcase_var.h"
64*64fbda90SVal Packett
65*64fbda90SVal Packett /*
66*64fbda90SVal Packett * XXX: The Linux driver only supports ACPI GPEs, but we only receive
67*64fbda90SVal Packett * interrupts in this driver on a MacBookPro 12,1 and 14,1. This is because
68*64fbda90SVal Packett * Linux responds to _OSI("Darwin") while we don't!
69*64fbda90SVal Packett *
70*64fbda90SVal Packett * ACPI GPE is enabled on FreeBSD by addition of following lines to
71*64fbda90SVal Packett * /boot/loader.conf:
72*64fbda90SVal Packett * hw.acpi.install_interface="Darwin"
73*64fbda90SVal Packett * hw.acpi.remove_interface="Windows 2009, Windows 2012"
74*64fbda90SVal Packett */
75*64fbda90SVal Packett
76*64fbda90SVal Packett static const char *atopcase_ids[] = { "APP000D", NULL };
77*64fbda90SVal Packett
78*64fbda90SVal Packett static device_probe_t atopcase_acpi_probe;
79*64fbda90SVal Packett static device_attach_t atopcase_acpi_attach;
80*64fbda90SVal Packett static device_detach_t atopcase_acpi_detach;
81*64fbda90SVal Packett static device_suspend_t atopcase_acpi_suspend;
82*64fbda90SVal Packett static device_resume_t atopcase_acpi_resume;
83*64fbda90SVal Packett
84*64fbda90SVal Packett static bool
acpi_is_atopcase(ACPI_HANDLE handle)85*64fbda90SVal Packett acpi_is_atopcase(ACPI_HANDLE handle)
86*64fbda90SVal Packett {
87*64fbda90SVal Packett const char **ids;
88*64fbda90SVal Packett UINT32 sta;
89*64fbda90SVal Packett
90*64fbda90SVal Packett for (ids = atopcase_ids; *ids != NULL; ids++) {
91*64fbda90SVal Packett if (acpi_MatchHid(handle, *ids))
92*64fbda90SVal Packett break;
93*64fbda90SVal Packett }
94*64fbda90SVal Packett if (*ids == NULL)
95*64fbda90SVal Packett return (false);
96*64fbda90SVal Packett
97*64fbda90SVal Packett /*
98*64fbda90SVal Packett * If no _STA method or if it failed, then assume that
99*64fbda90SVal Packett * the device is present.
100*64fbda90SVal Packett */
101*64fbda90SVal Packett if (ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) ||
102*64fbda90SVal Packett ACPI_DEVICE_PRESENT(sta))
103*64fbda90SVal Packett return (true);
104*64fbda90SVal Packett
105*64fbda90SVal Packett return (false);
106*64fbda90SVal Packett }
107*64fbda90SVal Packett
108*64fbda90SVal Packett static int
atopcase_acpi_set_comm_enabled(struct atopcase_softc * sc,char * prop,const bool on)109*64fbda90SVal Packett atopcase_acpi_set_comm_enabled(struct atopcase_softc *sc, char *prop,
110*64fbda90SVal Packett const bool on)
111*64fbda90SVal Packett {
112*64fbda90SVal Packett ACPI_OBJECT argobj;
113*64fbda90SVal Packett ACPI_OBJECT_LIST args;
114*64fbda90SVal Packett
115*64fbda90SVal Packett argobj.Type = ACPI_TYPE_INTEGER;
116*64fbda90SVal Packett argobj.Integer.Value = on;
117*64fbda90SVal Packett args.Count = 1;
118*64fbda90SVal Packett args.Pointer = &argobj;
119*64fbda90SVal Packett
120*64fbda90SVal Packett if (ACPI_FAILURE(
121*64fbda90SVal Packett AcpiEvaluateObject(sc->sc_handle, prop, &args, NULL)))
122*64fbda90SVal Packett return (ENXIO);
123*64fbda90SVal Packett
124*64fbda90SVal Packett DELAY(100);
125*64fbda90SVal Packett
126*64fbda90SVal Packett return (0);
127*64fbda90SVal Packett }
128*64fbda90SVal Packett
129*64fbda90SVal Packett static int
atopcase_acpi_test_comm_enabled(ACPI_HANDLE handle,char * prop,int * enabled)130*64fbda90SVal Packett atopcase_acpi_test_comm_enabled(ACPI_HANDLE handle, char *prop, int *enabled)
131*64fbda90SVal Packett {
132*64fbda90SVal Packett if (ACPI_FAILURE(acpi_GetInteger(handle, prop, enabled)))
133*64fbda90SVal Packett return (ENXIO);
134*64fbda90SVal Packett
135*64fbda90SVal Packett return (0);
136*64fbda90SVal Packett }
137*64fbda90SVal Packett
138*64fbda90SVal Packett static void
atopcase_acpi_task(void * ctx,int pending __unused)139*64fbda90SVal Packett atopcase_acpi_task(void *ctx, int pending __unused)
140*64fbda90SVal Packett {
141*64fbda90SVal Packett struct atopcase_softc *sc = ctx;
142*64fbda90SVal Packett int err = EAGAIN;
143*64fbda90SVal Packett
144*64fbda90SVal Packett DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "Timer event\n");
145*64fbda90SVal Packett
146*64fbda90SVal Packett sx_xlock(&sc->sc_write_sx);
147*64fbda90SVal Packett err = atopcase_receive_packet(sc);
148*64fbda90SVal Packett sx_xunlock(&sc->sc_write_sx);
149*64fbda90SVal Packett
150*64fbda90SVal Packett /* Rearm timer */
151*64fbda90SVal Packett taskqueue_enqueue_timeout(sc->sc_tq, &sc->sc_task,
152*64fbda90SVal Packett hz / (err == EAGAIN ? 10 : 120));
153*64fbda90SVal Packett }
154*64fbda90SVal Packett
155*64fbda90SVal Packett static void
atopcase_acpi_gpe_task(void * ctx)156*64fbda90SVal Packett atopcase_acpi_gpe_task(void *ctx)
157*64fbda90SVal Packett {
158*64fbda90SVal Packett struct atopcase_softc *sc = ctx;
159*64fbda90SVal Packett
160*64fbda90SVal Packett DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "GPE event\n");
161*64fbda90SVal Packett
162*64fbda90SVal Packett sx_xlock(&sc->sc_sx);
163*64fbda90SVal Packett (void)atopcase_intr(sc);
164*64fbda90SVal Packett sx_xunlock(&sc->sc_sx);
165*64fbda90SVal Packett
166*64fbda90SVal Packett /* Rearm GPE */
167*64fbda90SVal Packett if (ACPI_FAILURE(AcpiFinishGpe(NULL, sc->sc_gpe_bit)))
168*64fbda90SVal Packett device_printf(sc->sc_dev, "GPE rearm failed\n");
169*64fbda90SVal Packett }
170*64fbda90SVal Packett
171*64fbda90SVal Packett static UINT32
atopcase_acpi_notify(ACPI_HANDLE h __unused,UINT32 notify __unused,void * ctx)172*64fbda90SVal Packett atopcase_acpi_notify(ACPI_HANDLE h __unused, UINT32 notify __unused, void *ctx)
173*64fbda90SVal Packett {
174*64fbda90SVal Packett AcpiOsExecute(OSL_GPE_HANDLER, atopcase_acpi_gpe_task, ctx);
175*64fbda90SVal Packett return (0);
176*64fbda90SVal Packett }
177*64fbda90SVal Packett
178*64fbda90SVal Packett static void
atopcase_acpi_intr(void * ctx)179*64fbda90SVal Packett atopcase_acpi_intr(void *ctx)
180*64fbda90SVal Packett {
181*64fbda90SVal Packett struct atopcase_softc *sc = ctx;
182*64fbda90SVal Packett
183*64fbda90SVal Packett DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "Interrupt event\n");
184*64fbda90SVal Packett
185*64fbda90SVal Packett mtx_lock(&sc->sc_mtx);
186*64fbda90SVal Packett sc->sc_intr_cnt++;
187*64fbda90SVal Packett (void)atopcase_intr(sc);
188*64fbda90SVal Packett mtx_unlock(&sc->sc_mtx);
189*64fbda90SVal Packett }
190*64fbda90SVal Packett
191*64fbda90SVal Packett static int
atopcase_acpi_probe(device_t dev)192*64fbda90SVal Packett atopcase_acpi_probe(device_t dev)
193*64fbda90SVal Packett {
194*64fbda90SVal Packett ACPI_HANDLE handle;
195*64fbda90SVal Packett int usb_enabled;
196*64fbda90SVal Packett
197*64fbda90SVal Packett if (acpi_disabled("atopcase"))
198*64fbda90SVal Packett return (ENXIO);
199*64fbda90SVal Packett
200*64fbda90SVal Packett handle = acpi_get_handle(dev);
201*64fbda90SVal Packett if (handle == NULL)
202*64fbda90SVal Packett return (ENXIO);
203*64fbda90SVal Packett
204*64fbda90SVal Packett if (!acpi_is_atopcase(handle))
205*64fbda90SVal Packett return (ENXIO);
206*64fbda90SVal Packett
207*64fbda90SVal Packett /* If USB interface exists and is enabled, use USB driver */
208*64fbda90SVal Packett if (atopcase_acpi_test_comm_enabled(handle, "UIST", &usb_enabled) == 0
209*64fbda90SVal Packett && usb_enabled != 0)
210*64fbda90SVal Packett return (ENXIO);
211*64fbda90SVal Packett
212*64fbda90SVal Packett device_set_desc(dev, "Apple MacBook SPI Topcase");
213*64fbda90SVal Packett
214*64fbda90SVal Packett return (BUS_PROBE_DEFAULT);
215*64fbda90SVal Packett }
216*64fbda90SVal Packett
217*64fbda90SVal Packett static int
atopcase_acpi_attach(device_t dev)218*64fbda90SVal Packett atopcase_acpi_attach(device_t dev)
219*64fbda90SVal Packett {
220*64fbda90SVal Packett struct atopcase_softc *sc = device_get_softc(dev);
221*64fbda90SVal Packett ACPI_DEVICE_INFO *device_info;
222*64fbda90SVal Packett uint32_t cs_delay;
223*64fbda90SVal Packett int spi_enabled, err;
224*64fbda90SVal Packett
225*64fbda90SVal Packett sc->sc_dev = dev;
226*64fbda90SVal Packett sc->sc_handle = acpi_get_handle(dev);
227*64fbda90SVal Packett
228*64fbda90SVal Packett if (atopcase_acpi_test_comm_enabled(sc->sc_handle, "SIST",
229*64fbda90SVal Packett &spi_enabled) != 0) {
230*64fbda90SVal Packett device_printf(dev, "can't test SPI communication\n");
231*64fbda90SVal Packett return (ENXIO);
232*64fbda90SVal Packett }
233*64fbda90SVal Packett
234*64fbda90SVal Packett /* Turn SPI off if enabled to force "booted" packet to appear */
235*64fbda90SVal Packett if (spi_enabled != 0 &&
236*64fbda90SVal Packett atopcase_acpi_set_comm_enabled(sc, "SIEN", false) != 0) {
237*64fbda90SVal Packett device_printf(dev, "can't disable SPI communication\n");
238*64fbda90SVal Packett return (ENXIO);
239*64fbda90SVal Packett }
240*64fbda90SVal Packett
241*64fbda90SVal Packett if (atopcase_acpi_set_comm_enabled(sc, "SIEN", true) != 0) {
242*64fbda90SVal Packett device_printf(dev, "can't enable SPI communication\n");
243*64fbda90SVal Packett return (ENXIO);
244*64fbda90SVal Packett }
245*64fbda90SVal Packett
246*64fbda90SVal Packett /*
247*64fbda90SVal Packett * Apple encodes a CS delay in ACPI properties, but
248*64fbda90SVal Packett * - they're encoded in a non-standard way that predates _DSD, and
249*64fbda90SVal Packett * - they're only exported if you respond to _OSI(Darwin) which we don't
250*64fbda90SVal Packett * - because that has more side effects than we're prepared to handle
251*64fbda90SVal Packett * - Apple makes a Windows driver and Windows is not Darwin
252*64fbda90SVal Packett * - so presumably that one uses hardcoded values too
253*64fbda90SVal Packett */
254*64fbda90SVal Packett spibus_get_cs_delay(sc->sc_dev, &cs_delay);
255*64fbda90SVal Packett if (cs_delay == 0)
256*64fbda90SVal Packett spibus_set_cs_delay(sc->sc_dev, 10);
257*64fbda90SVal Packett
258*64fbda90SVal Packett /* Retrieve ACPI _HID */
259*64fbda90SVal Packett if (ACPI_FAILURE(AcpiGetObjectInfo(sc->sc_handle, &device_info)))
260*64fbda90SVal Packett return (ENXIO);
261*64fbda90SVal Packett if (device_info->Valid & ACPI_VALID_HID)
262*64fbda90SVal Packett strlcpy(sc->sc_hid, device_info->HardwareId.String,
263*64fbda90SVal Packett sizeof(sc->sc_hid));
264*64fbda90SVal Packett AcpiOsFree(device_info);
265*64fbda90SVal Packett
266*64fbda90SVal Packett sx_init(&sc->sc_write_sx, "atc_wr");
267*64fbda90SVal Packett sx_init(&sc->sc_sx, "atc_sx");
268*64fbda90SVal Packett mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
269*64fbda90SVal Packett
270*64fbda90SVal Packett err = ENXIO;
271*64fbda90SVal Packett sc->sc_irq_res = bus_alloc_resource_any(sc->sc_dev,
272*64fbda90SVal Packett SYS_RES_IRQ, &sc->sc_irq_rid, RF_ACTIVE);
273*64fbda90SVal Packett if (sc->sc_irq_res != NULL) {
274*64fbda90SVal Packett if (bus_setup_intr(dev, sc->sc_irq_res,
275*64fbda90SVal Packett INTR_TYPE_MISC | INTR_MPSAFE, NULL,
276*64fbda90SVal Packett atopcase_acpi_intr, sc, &sc->sc_irq_ih) != 0) {
277*64fbda90SVal Packett device_printf(dev, "can't setup interrupt handler\n");
278*64fbda90SVal Packett goto err;
279*64fbda90SVal Packett }
280*64fbda90SVal Packett device_printf(dev, "Using interrupts.\n");
281*64fbda90SVal Packett /*
282*64fbda90SVal Packett * On some hardware interrupts are not acked by SPI read for
283*64fbda90SVal Packett * unknown reasons that leads to interrupt storm due to level
284*64fbda90SVal Packett * triggering. GPE does not suffer from this problem.
285*64fbda90SVal Packett *
286*64fbda90SVal Packett * TODO: Find out what Windows driver does to ack IRQ.
287*64fbda90SVal Packett */
288*64fbda90SVal Packett pause("atopcase", hz / 5);
289*64fbda90SVal Packett DPRINTF("interrupts asserted: %u\n", sc->sc_intr_cnt);
290*64fbda90SVal Packett if (sc->sc_intr_cnt > 2 || sc->sc_intr_cnt == 0) {
291*64fbda90SVal Packett bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_ih);
292*64fbda90SVal Packett sc->sc_irq_ih = NULL;
293*64fbda90SVal Packett device_printf(dev, "Interrupt storm detected. "
294*64fbda90SVal Packett "Falling back to polling\n");
295*64fbda90SVal Packett sc->sc_tq = taskqueue_create("atc_tq", M_WAITOK|M_ZERO,
296*64fbda90SVal Packett taskqueue_thread_enqueue, &sc->sc_tq);
297*64fbda90SVal Packett TIMEOUT_TASK_INIT(sc->sc_tq, &sc->sc_task, 0,
298*64fbda90SVal Packett atopcase_acpi_task, sc);
299*64fbda90SVal Packett taskqueue_start_threads(&sc->sc_tq, 1, PI_TTY,
300*64fbda90SVal Packett "%s taskq", device_get_nameunit(dev));
301*64fbda90SVal Packett }
302*64fbda90SVal Packett /*
303*64fbda90SVal Packett * Interrupts does not work at all. It may happen if kernel
304*64fbda90SVal Packett * erroneously detected stray irq at bus_teardown_intr() and
305*64fbda90SVal Packett * completelly disabled it after than.
306*64fbda90SVal Packett * Fetch "booted" packet manually to pass communication check.
307*64fbda90SVal Packett */
308*64fbda90SVal Packett if (sc->sc_intr_cnt == 0)
309*64fbda90SVal Packett atopcase_receive_packet(sc);
310*64fbda90SVal Packett } else {
311*64fbda90SVal Packett if (bootverbose)
312*64fbda90SVal Packett device_printf(dev, "can't allocate IRQ resource\n");
313*64fbda90SVal Packett if (ACPI_FAILURE(acpi_GetInteger(sc->sc_handle, "_GPE",
314*64fbda90SVal Packett &sc->sc_gpe_bit))) {
315*64fbda90SVal Packett device_printf(dev, "can't allocate nor IRQ nor GPE\n");
316*64fbda90SVal Packett goto err;
317*64fbda90SVal Packett }
318*64fbda90SVal Packett if (ACPI_FAILURE(AcpiInstallGpeHandler(NULL, sc->sc_gpe_bit,
319*64fbda90SVal Packett ACPI_GPE_LEVEL_TRIGGERED, atopcase_acpi_notify, sc))) {
320*64fbda90SVal Packett device_printf(dev, "can't install ACPI GPE handler\n");
321*64fbda90SVal Packett goto err;
322*64fbda90SVal Packett }
323*64fbda90SVal Packett if (ACPI_FAILURE(AcpiEnableGpe(NULL, sc->sc_gpe_bit))) {
324*64fbda90SVal Packett device_printf(dev, "can't enable ACPI notification\n");
325*64fbda90SVal Packett goto err;
326*64fbda90SVal Packett }
327*64fbda90SVal Packett device_printf(dev, "Using ACPI GPE.\n");
328*64fbda90SVal Packett if (bootverbose)
329*64fbda90SVal Packett device_printf(dev, "GPE int %d\n", sc->sc_gpe_bit);
330*64fbda90SVal Packett }
331*64fbda90SVal Packett
332*64fbda90SVal Packett err = atopcase_init(sc);
333*64fbda90SVal Packett
334*64fbda90SVal Packett err:
335*64fbda90SVal Packett if (err != 0)
336*64fbda90SVal Packett atopcase_acpi_detach(dev);
337*64fbda90SVal Packett return (err);
338*64fbda90SVal Packett }
339*64fbda90SVal Packett
340*64fbda90SVal Packett static int
atopcase_acpi_detach(device_t dev)341*64fbda90SVal Packett atopcase_acpi_detach(device_t dev)
342*64fbda90SVal Packett {
343*64fbda90SVal Packett struct atopcase_softc *sc = device_get_softc(dev);
344*64fbda90SVal Packett int err;
345*64fbda90SVal Packett
346*64fbda90SVal Packett err = atopcase_destroy(sc);
347*64fbda90SVal Packett if (err != 0)
348*64fbda90SVal Packett return (err);
349*64fbda90SVal Packett
350*64fbda90SVal Packett if (sc->sc_irq_ih)
351*64fbda90SVal Packett bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_ih);
352*64fbda90SVal Packett if (sc->sc_irq_res != NULL)
353*64fbda90SVal Packett bus_release_resource(dev, SYS_RES_IRQ,
354*64fbda90SVal Packett sc->sc_irq_rid, sc->sc_irq_res);
355*64fbda90SVal Packett
356*64fbda90SVal Packett if (sc->sc_tq != NULL) {
357*64fbda90SVal Packett while (taskqueue_cancel_timeout(sc->sc_tq, &sc->sc_task, NULL))
358*64fbda90SVal Packett taskqueue_drain_timeout(sc->sc_tq, &sc->sc_task);
359*64fbda90SVal Packett taskqueue_free(sc->sc_tq);
360*64fbda90SVal Packett }
361*64fbda90SVal Packett
362*64fbda90SVal Packett if (sc->sc_gpe_bit != 0 && ACPI_FAILURE(AcpiRemoveGpeHandler(NULL,
363*64fbda90SVal Packett sc->sc_gpe_bit, atopcase_acpi_notify)))
364*64fbda90SVal Packett device_printf(dev, "can't remove ACPI GPE handler\n");
365*64fbda90SVal Packett
366*64fbda90SVal Packett if (atopcase_acpi_set_comm_enabled(sc, "SIEN", false) != 0)
367*64fbda90SVal Packett device_printf(dev, "can't disable SPI communication\n");
368*64fbda90SVal Packett
369*64fbda90SVal Packett mtx_destroy(&sc->sc_mtx);
370*64fbda90SVal Packett sx_destroy(&sc->sc_sx);
371*64fbda90SVal Packett sx_destroy(&sc->sc_write_sx);
372*64fbda90SVal Packett
373*64fbda90SVal Packett return (0);
374*64fbda90SVal Packett }
375*64fbda90SVal Packett
376*64fbda90SVal Packett static int
atopcase_acpi_suspend(device_t dev)377*64fbda90SVal Packett atopcase_acpi_suspend(device_t dev)
378*64fbda90SVal Packett {
379*64fbda90SVal Packett struct atopcase_softc *sc = device_get_softc(dev);
380*64fbda90SVal Packett int err;
381*64fbda90SVal Packett
382*64fbda90SVal Packett err = bus_generic_suspend(dev);
383*64fbda90SVal Packett if (err)
384*64fbda90SVal Packett return (err);
385*64fbda90SVal Packett
386*64fbda90SVal Packett if (sc->sc_gpe_bit != 0)
387*64fbda90SVal Packett AcpiDisableGpe(NULL, sc->sc_gpe_bit);
388*64fbda90SVal Packett
389*64fbda90SVal Packett if (sc->sc_tq != NULL)
390*64fbda90SVal Packett while (taskqueue_cancel_timeout(sc->sc_tq, &sc->sc_task, NULL))
391*64fbda90SVal Packett taskqueue_drain_timeout(sc->sc_tq, &sc->sc_task);
392*64fbda90SVal Packett
393*64fbda90SVal Packett if (atopcase_acpi_set_comm_enabled(sc, "SIEN", false) != 0)
394*64fbda90SVal Packett device_printf(dev, "can't disable SPI communication\n");
395*64fbda90SVal Packett
396*64fbda90SVal Packett return (0);
397*64fbda90SVal Packett }
398*64fbda90SVal Packett
399*64fbda90SVal Packett static int
atopcase_acpi_resume(device_t dev)400*64fbda90SVal Packett atopcase_acpi_resume(device_t dev)
401*64fbda90SVal Packett {
402*64fbda90SVal Packett struct atopcase_softc *sc = device_get_softc(dev);
403*64fbda90SVal Packett
404*64fbda90SVal Packett if (sc->sc_gpe_bit != 0)
405*64fbda90SVal Packett AcpiEnableGpe(NULL, sc->sc_gpe_bit);
406*64fbda90SVal Packett
407*64fbda90SVal Packett if (sc->sc_tq != NULL)
408*64fbda90SVal Packett taskqueue_enqueue_timeout(sc->sc_tq, &sc->sc_task, hz / 120);
409*64fbda90SVal Packett
410*64fbda90SVal Packett if (atopcase_acpi_set_comm_enabled(sc, "SIEN", true) != 0) {
411*64fbda90SVal Packett device_printf(dev, "can't enable SPI communication\n");
412*64fbda90SVal Packett return (ENXIO);
413*64fbda90SVal Packett }
414*64fbda90SVal Packett
415*64fbda90SVal Packett return (bus_generic_resume(dev));
416*64fbda90SVal Packett }
417*64fbda90SVal Packett
418*64fbda90SVal Packett static device_method_t atopcase_methods[] = {
419*64fbda90SVal Packett /* Device interface */
420*64fbda90SVal Packett DEVMETHOD(device_probe, atopcase_acpi_probe),
421*64fbda90SVal Packett DEVMETHOD(device_attach, atopcase_acpi_attach),
422*64fbda90SVal Packett DEVMETHOD(device_detach, atopcase_acpi_detach),
423*64fbda90SVal Packett DEVMETHOD(device_suspend, atopcase_acpi_suspend),
424*64fbda90SVal Packett DEVMETHOD(device_resume, atopcase_acpi_resume),
425*64fbda90SVal Packett
426*64fbda90SVal Packett /* HID interrupt interface */
427*64fbda90SVal Packett DEVMETHOD(hid_intr_setup, atopcase_intr_setup),
428*64fbda90SVal Packett DEVMETHOD(hid_intr_unsetup, atopcase_intr_unsetup),
429*64fbda90SVal Packett DEVMETHOD(hid_intr_start, atopcase_intr_start),
430*64fbda90SVal Packett DEVMETHOD(hid_intr_stop, atopcase_intr_stop),
431*64fbda90SVal Packett DEVMETHOD(hid_intr_poll, atopcase_intr_poll),
432*64fbda90SVal Packett
433*64fbda90SVal Packett /* HID interface */
434*64fbda90SVal Packett DEVMETHOD(hid_get_rdesc, atopcase_get_rdesc),
435*64fbda90SVal Packett DEVMETHOD(hid_set_report, atopcase_set_report),
436*64fbda90SVal Packett
437*64fbda90SVal Packett /* Backlight interface */
438*64fbda90SVal Packett DEVMETHOD(backlight_update_status, atopcase_backlight_update_status),
439*64fbda90SVal Packett DEVMETHOD(backlight_get_status, atopcase_backlight_get_status),
440*64fbda90SVal Packett DEVMETHOD(backlight_get_info, atopcase_backlight_get_info),
441*64fbda90SVal Packett
442*64fbda90SVal Packett DEVMETHOD_END
443*64fbda90SVal Packett };
444*64fbda90SVal Packett
445*64fbda90SVal Packett static driver_t atopcase_driver = {
446*64fbda90SVal Packett "atopcase",
447*64fbda90SVal Packett atopcase_methods,
448*64fbda90SVal Packett sizeof(struct atopcase_softc),
449*64fbda90SVal Packett };
450*64fbda90SVal Packett
451*64fbda90SVal Packett DRIVER_MODULE(atopcase, spibus, atopcase_driver, 0, 0);
452*64fbda90SVal Packett MODULE_DEPEND(atopcase, acpi, 1, 1, 1);
453*64fbda90SVal Packett MODULE_DEPEND(atopcase, backlight, 1, 1, 1);
454*64fbda90SVal Packett MODULE_DEPEND(atopcase, hid, 1, 1, 1);
455*64fbda90SVal Packett MODULE_DEPEND(atopcase, hidbus, 1, 1, 1);
456*64fbda90SVal Packett MODULE_DEPEND(atopcase, spibus, 1, 1, 1);
457*64fbda90SVal Packett MODULE_VERSION(atopcase, 1);
458*64fbda90SVal Packett SPIBUS_ACPI_PNP_INFO(atopcase_ids);
459