xref: /openbsd-src/sys/dev/acpi/acpials.c (revision 85fcfc35df4a58ba20bf8a539339bc9ad114950e)
1*85fcfc35Svisa /* $OpenBSD: acpials.c,v 1.4 2020/08/26 03:29:06 visa Exp $ */
250e2d8d7Sjcs /*
350e2d8d7Sjcs  * Ambient Light Sensor device driver
450e2d8d7Sjcs  * ACPI 5.0 spec section 9.2
550e2d8d7Sjcs  *
650e2d8d7Sjcs  * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
750e2d8d7Sjcs  *
850e2d8d7Sjcs  * Permission to use, copy, modify, and distribute this software for any
950e2d8d7Sjcs  * purpose with or without fee is hereby granted, provided that the above
1050e2d8d7Sjcs  * copyright notice and this permission notice appear in all copies.
1150e2d8d7Sjcs  *
1250e2d8d7Sjcs  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1350e2d8d7Sjcs  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1450e2d8d7Sjcs  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1550e2d8d7Sjcs  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1650e2d8d7Sjcs  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1750e2d8d7Sjcs  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1850e2d8d7Sjcs  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1950e2d8d7Sjcs  */
2050e2d8d7Sjcs 
2150e2d8d7Sjcs #include <sys/param.h>
2250e2d8d7Sjcs #include <sys/systm.h>
2350e2d8d7Sjcs #include <sys/device.h>
2450e2d8d7Sjcs 
2550e2d8d7Sjcs #include <dev/acpi/acpireg.h>
2650e2d8d7Sjcs #include <dev/acpi/acpivar.h>
2750e2d8d7Sjcs #include <dev/acpi/acpidev.h>
2850e2d8d7Sjcs #include <dev/acpi/amltypes.h>
2950e2d8d7Sjcs #include <dev/acpi/dsdt.h>
3050e2d8d7Sjcs 
3150e2d8d7Sjcs #include <sys/sensors.h>
3250e2d8d7Sjcs 
3350e2d8d7Sjcs /* #define ACPIALS_DEBUG */
3450e2d8d7Sjcs 
3550e2d8d7Sjcs #ifdef ACPIALS_DEBUG
3650e2d8d7Sjcs #define DPRINTF(x) printf x
3750e2d8d7Sjcs #else
3850e2d8d7Sjcs #define DPRINTF(x)
3950e2d8d7Sjcs #endif
4050e2d8d7Sjcs 
4150e2d8d7Sjcs struct acpials_softc {
4250e2d8d7Sjcs 	struct device		sc_dev;
4350e2d8d7Sjcs 
4450e2d8d7Sjcs 	bus_space_tag_t		sc_iot;
4550e2d8d7Sjcs 	bus_space_handle_t	sc_ioh;
4650e2d8d7Sjcs 
4750e2d8d7Sjcs 	struct acpi_softc	*sc_acpi;
4850e2d8d7Sjcs 	struct aml_node		*sc_devnode;
4950e2d8d7Sjcs 
5050e2d8d7Sjcs 	struct ksensor		sc_sensor;
5150e2d8d7Sjcs 	struct ksensordev	sc_sensordev;
5250e2d8d7Sjcs 	struct sensor_task	*sc_sensor_task;
5350e2d8d7Sjcs };
5450e2d8d7Sjcs 
5550e2d8d7Sjcs int	acpials_match(struct device *, void *, void *);
5650e2d8d7Sjcs void	acpials_attach(struct device *, struct device *, void *);
5750e2d8d7Sjcs int	acpials_read(struct acpials_softc *);
5850e2d8d7Sjcs int	acpials_notify(struct aml_node *, int, void *);
5950e2d8d7Sjcs void	acpials_addtask(void *);
6050e2d8d7Sjcs void	acpials_update(void *, int);
6150e2d8d7Sjcs 
62d24e5186Sjcs const struct cfattach acpials_ca = {
6350e2d8d7Sjcs 	sizeof(struct acpials_softc),
6450e2d8d7Sjcs 	acpials_match,
6550e2d8d7Sjcs 	acpials_attach,
6650e2d8d7Sjcs };
6750e2d8d7Sjcs 
6850e2d8d7Sjcs struct cfdriver acpials_cd = {
6950e2d8d7Sjcs 	NULL, "acpials", DV_DULL
7050e2d8d7Sjcs };
7150e2d8d7Sjcs 
7250e2d8d7Sjcs const char *acpials_hids[] = {
7350e2d8d7Sjcs 	"ACPI0008",
748816acbcSkettenis 	NULL
7550e2d8d7Sjcs };
7650e2d8d7Sjcs 
7750e2d8d7Sjcs int
acpials_match(struct device * parent,void * match,void * aux)7850e2d8d7Sjcs acpials_match(struct device *parent, void *match, void *aux)
7950e2d8d7Sjcs {
8050e2d8d7Sjcs 	struct acpi_attach_args *aa = aux;
8150e2d8d7Sjcs 	struct cfdata *cf = match;
8250e2d8d7Sjcs 
83d24e5186Sjcs 	/*
84d24e5186Sjcs 	 * Apple hardware will most likely have asmc(4) which also provides an
85d24e5186Sjcs 	 * illuminance sensor.
86d24e5186Sjcs 	 */
87d24e5186Sjcs 	if (hw_vendor != NULL && strncmp(hw_vendor, "Apple", 5) == 0)
88d24e5186Sjcs 		return 0;
89d24e5186Sjcs 
9050e2d8d7Sjcs 	return (acpi_matchhids(aa, acpials_hids, cf->cf_driver->cd_name));
9150e2d8d7Sjcs }
9250e2d8d7Sjcs 
9350e2d8d7Sjcs void
acpials_attach(struct device * parent,struct device * self,void * aux)9450e2d8d7Sjcs acpials_attach(struct device *parent, struct device *self, void *aux)
9550e2d8d7Sjcs {
9650e2d8d7Sjcs 	struct acpials_softc *sc = (struct acpials_softc *)self;
9750e2d8d7Sjcs 	struct acpi_attach_args *aa = aux;
9850e2d8d7Sjcs 	int64_t st;
9950e2d8d7Sjcs 
10050e2d8d7Sjcs 	sc->sc_acpi = (struct acpi_softc *)parent;
10150e2d8d7Sjcs 	sc->sc_devnode = aa->aaa_node;
10250e2d8d7Sjcs 
10350e2d8d7Sjcs 	printf(": %s\n", sc->sc_devnode->name);
10450e2d8d7Sjcs 
10550e2d8d7Sjcs 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
10650e2d8d7Sjcs 		st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
10750e2d8d7Sjcs 	if ((st & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
10850e2d8d7Sjcs 	    (STA_PRESENT | STA_ENABLED | STA_DEV_OK))
10950e2d8d7Sjcs 		return;
11050e2d8d7Sjcs 
11150e2d8d7Sjcs 	if (acpials_read(sc))
11250e2d8d7Sjcs 		return;
11350e2d8d7Sjcs 
11450e2d8d7Sjcs 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
11550e2d8d7Sjcs 	    sizeof(sc->sc_sensordev.xname));
11650e2d8d7Sjcs 	strlcpy(sc->sc_sensor.desc, "ambient light sensor",
11750e2d8d7Sjcs 	    sizeof(sc->sc_sensor.desc));
11850e2d8d7Sjcs 	sc->sc_sensor.type = SENSOR_LUX;
11950e2d8d7Sjcs 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
12050e2d8d7Sjcs 
12150e2d8d7Sjcs 	/*
12250e2d8d7Sjcs 	 * aml_register_notify with ACPIDEV_POLL is too slow (10 second
12350e2d8d7Sjcs 	 * intervals), so register the task with sensors so we can specify the
12450e2d8d7Sjcs 	 * interval, which will then just inject an acpi task and tell it to
12550e2d8d7Sjcs 	 * wakeup to handle the task.
12650e2d8d7Sjcs 	 */
12750e2d8d7Sjcs 	if (!(sc->sc_sensor_task = sensor_task_register(sc, acpials_addtask,
12850e2d8d7Sjcs 	    1))) {
12950e2d8d7Sjcs 		printf("%s: unable to register task\n", sc->sc_dev.dv_xname);
13050e2d8d7Sjcs 		return;
13150e2d8d7Sjcs 	}
13250e2d8d7Sjcs 
13350e2d8d7Sjcs 	/*
13450e2d8d7Sjcs 	 * But also install an event handler in case AML Notify()s us of any
13550e2d8d7Sjcs 	 * large changes - 9.2.7
13650e2d8d7Sjcs 	 */
13750e2d8d7Sjcs 	aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpials_notify,
13850e2d8d7Sjcs 	    sc, ACPIDEV_NOPOLL);
13950e2d8d7Sjcs 
14050e2d8d7Sjcs 	sensordev_install(&sc->sc_sensordev);
14150e2d8d7Sjcs }
14250e2d8d7Sjcs 
14350e2d8d7Sjcs int
acpials_read(struct acpials_softc * sc)14450e2d8d7Sjcs acpials_read(struct acpials_softc *sc)
14550e2d8d7Sjcs {
14650e2d8d7Sjcs 	int64_t	ali = 0;
14750e2d8d7Sjcs 
14850e2d8d7Sjcs 	/* 9.2.2 - "Current ambient light illuminance reading in lux" */
14950e2d8d7Sjcs 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_ALI", 0, NULL,
15050e2d8d7Sjcs 	    &ali))
15150e2d8d7Sjcs 		return 1;
15250e2d8d7Sjcs 
15350e2d8d7Sjcs 	sc->sc_sensor.value = (ali * 1000000);
15450e2d8d7Sjcs 
15550e2d8d7Sjcs 	return 0;
15650e2d8d7Sjcs }
15750e2d8d7Sjcs 
15850e2d8d7Sjcs int
acpials_notify(struct aml_node * node,int notify_type,void * arg)15950e2d8d7Sjcs acpials_notify(struct aml_node *node, int notify_type, void *arg)
16050e2d8d7Sjcs {
16150e2d8d7Sjcs 	struct acpials_softc *sc = arg;
16250e2d8d7Sjcs 
16350e2d8d7Sjcs 	DPRINTF(("%s: %s: %d\n", sc->sc_dev.dv_xname, __func__, notify_type));
16450e2d8d7Sjcs 
16550e2d8d7Sjcs 	if (notify_type == 0x80)
16650e2d8d7Sjcs 		acpials_read(sc);
16750e2d8d7Sjcs 
16850e2d8d7Sjcs 	return 0;
16950e2d8d7Sjcs }
17050e2d8d7Sjcs 
17150e2d8d7Sjcs void
acpials_addtask(void * arg)17250e2d8d7Sjcs acpials_addtask(void *arg)
17350e2d8d7Sjcs {
17450e2d8d7Sjcs 	struct acpials_softc *sc = arg;
17550e2d8d7Sjcs 
17650e2d8d7Sjcs 	acpi_addtask(sc->sc_acpi, acpials_update, sc, 0);
17750e2d8d7Sjcs 	acpi_wakeup(sc->sc_acpi);
17850e2d8d7Sjcs }
17950e2d8d7Sjcs 
18050e2d8d7Sjcs void
acpials_update(void * arg0,int arg1)18150e2d8d7Sjcs acpials_update(void *arg0, int arg1)
18250e2d8d7Sjcs {
18350e2d8d7Sjcs 	struct acpials_softc *sc = arg0;
18450e2d8d7Sjcs 
18550e2d8d7Sjcs 	if (acpials_read(sc) == 0) {
18650e2d8d7Sjcs 		DPRINTF(("%s: %s: %lld\n", sc->sc_dev.dv_xname, __func__,
18750e2d8d7Sjcs 		    sc->sc_sensor.value));
18850e2d8d7Sjcs 		sc->sc_sensor.flags &= ~SENSOR_FINVALID;
18950e2d8d7Sjcs 	} else
19050e2d8d7Sjcs 		sc->sc_sensor.flags |= SENSOR_FINVALID;
19150e2d8d7Sjcs }
192