tech-misc archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Ambient light drivers
Hi.
Together with Grégoire we tried to get an ambient light sensor on his laptop
to report something for the operating system. But we failed.
Couple of drivers were written in the process. I'll post them here so that
these are archived if someone finds them useful some day. The first one is
an ACPI driver identified with the ACPI0008 PNP string. The second one is
an I2C driver for the ISL29018 chip from Intersil.
- Jukka
/* $NetBSD$ */
/*-
* Copyright (c) 2011 Jukka Ruohonen <jruohonen%iki.fi@localhost>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi_als.c,v 1.4 2011/02/16 09:05:12 xxx Exp $");
#include <sys/param.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#include <dev/sysmon/sysmonvar.h>
#define _COMPONENT ACPI_RESOURCE_COMPONENT
ACPI_MODULE_NAME ("acpi_als")
#define ACPI_ALS_SENSOR_ILLUM 0
#define ACPI_ALS_SENSOR_TEMP 1
#define ACPI_ALS_SENSOR_CHROM_X 2
#define ACPI_ALS_SENSOR_CHROM_Y 3
#define ACPI_ALS_SENSOR_COUNT 4
#define ACPI_ALS_CHROM_X(x) (((x) & 0xffff0000) >> 16)
#define ACPI_ALS_CHROM_Y(y) (((y) & 0x0000ffff))
#define ACPI_ALS_CHROM_MAX 0x2710
#define ACPI_ALS_CHROM_TOPER(x) (((x) * 100) / ACPI_ALS_CHROM_MAX)
#define ACPI_ALS_NOTIFY_ILLUM 0x80
#define ACPI_ALS_NOTIFY_TEMP 0x81
#define ACPI_ALS_NOTIFY_RESP 0x82
struct acpials_softc {
device_t sc_dev;
struct acpi_devnode *sc_node;
struct sysmon_envsys *sc_sme;
envsys_data_t sc_sensor[ACPI_ALS_SENSOR_COUNT];
kmutex_t sc_mtx;
};
const char * const acpi_als_ids[] = {
"ACPI0008",
NULL
};
static int acpials_match(device_t, cfdata_t, void *);
static void acpials_attach(device_t, device_t, void *);
static int acpials_detach(device_t, int);
static int acpials_sensor_init(device_t);
static int32_t acpials_sensor_get(device_t, const char *);
static int32_t acpials_sensor_get_illuminance(device_t);
static int32_t acpials_sensor_get_temperature(device_t);
static int32_t acpials_sensor_get_chromaticity(device_t);
static void acpials_sensor_refresh(struct sysmon_envsys *,envsys_data_t *);
static void acpials_sensor_update(device_t, envsys_data_t *);
static void acpials_notify_handler(ACPI_HANDLE, uint32_t, void *);
CFATTACH_DECL_NEW(acpials, sizeof(struct acpials_softc),
acpials_match, acpials_attach, acpials_detach, NULL);
static int
acpials_match(device_t parent, cfdata_t match, void *aux)
{
struct acpi_attach_args *aa = aux;
if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
return 0;
return acpi_match_hid(aa->aa_node->ad_devinfo, acpi_als_ids);
}
static void
acpials_attach(device_t parent, device_t self, void *aux)
{
struct acpials_softc *sc = device_private(self);
struct acpi_attach_args *aa = aux;
ACPI_INTEGER val = 0;
ACPI_STATUS rv;
sc->sc_sme = NULL;
sc->sc_dev = self;
sc->sc_node = aa->aa_node;
aprint_naive("\n");
aprint_normal(": ACPI Ambient Light Sensor\n");
mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_NONE);
(void)acpials_sensor_init(self);
(void)pmf_device_register(self, NULL, NULL);
(void)acpi_register_notify(sc->sc_node, acpials_notify_handler);
rv = acpi_eval_integer(sc->sc_node->ad_handle, "_ALP", &val);
if (ACPI_SUCCESS(rv) && val != 0 && val < INT_MAX) {
aprint_debug_dev(self, "polling interval "
"%d.%d seconds\n", (int)val / 10, (int)val % 10);
}
}
static int
acpials_detach(device_t self, int flags)
{
struct acpials_softc *sc = device_private(self);
pmf_device_deregister(self);
acpi_deregister_notify(sc->sc_node);
if (sc->sc_sme != NULL)
sysmon_envsys_unregister(sc->sc_sme);
mutex_destroy(&sc->sc_mtx);
return 0;
}
static int
acpials_sensor_init(device_t self)
{
struct acpials_softc *sc = device_private(self);
envsys_data_t *sensor;
int32_t val;
sc->sc_sme = sysmon_envsys_create();
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_flags = SME_POLL_ONLY;
sc->sc_sme->sme_name = device_xname(self);
sc->sc_sme->sme_refresh = acpials_sensor_refresh;
val = acpials_sensor_get_illuminance(self);
if (val != -1) {
sensor = &sc->sc_sensor[ACPI_ALS_SENSOR_ILLUM];
sensor->state = ENVSYS_SVALID;
sensor->units = ENVSYS_INTEGER;
sensor->value_cur = val;
(void)strlcpy(sensor->desc, "illuminance", ENVSYS_DESCLEN);
(void)sysmon_envsys_sensor_attach(sc->sc_sme, sensor);
}
val = acpials_sensor_get_temperature(self);
if (val != -1) {
sensor = &sc->sc_sensor[ACPI_ALS_SENSOR_TEMP];
sensor->state = ENVSYS_SVALID;
sensor->units = ENVSYS_STEMP;
sensor->value_cur = val;
(void)strlcpy(sensor->desc, "temperature", ENVSYS_DESCLEN);
(void)sysmon_envsys_sensor_attach(sc->sc_sme, sensor);
}
val = acpials_sensor_get_chromaticity(self);
if (val != -1) {
sensor = &sc->sc_sensor[ACPI_ALS_SENSOR_CHROM_X];
sensor->state = ENVSYS_SVALID;
sensor->units = ENVSYS_INTEGER;
val = ACPI_ALS_CHROM_X(val);
sensor->value_cur = ACPI_ALS_CHROM_TOPER(val);
(void)strlcpy(sensor->desc, "x-chromaticity", ENVSYS_DESCLEN);
(void)sysmon_envsys_sensor_attach(sc->sc_sme, sensor);
sensor = &sc->sc_sensor[ACPI_ALS_SENSOR_CHROM_Y];
sensor->state = ENVSYS_SVALID;
sensor->units = ENVSYS_INTEGER;
val = ACPI_ALS_CHROM_Y(val);
sensor->value_cur = ACPI_ALS_CHROM_TOPER(val);
(void)strlcpy(sensor->desc, "y-chromaticity", ENVSYS_DESCLEN);
(void)sysmon_envsys_sensor_attach(sc->sc_sme, sensor);
}
if (sc->sc_sme->sme_nsensors == 0) {
aprint_error_dev(self, "no sensors found\n");
sysmon_envsys_destroy(sc->sc_sme);
sc->sc_sme = NULL;
return -1;
}
return sysmon_envsys_register(sc->sc_sme);
}
static int32_t
acpials_sensor_get(device_t self, const char *path)
{
struct acpials_softc *sc = device_private(self);
ACPI_INTEGER val = 0;
ACPI_STATUS rv;
rv = acpi_eval_integer(sc->sc_node->ad_handle, path, &val);
if (ACPI_FAILURE(rv))
goto fail;
if (val == 0 || val > INT32_MAX) {
rv = AE_BAD_VALUE;
goto fail;
}
return val;
fail:
aprint_debug_dev(self, "failed to evaluate "
"%s: %s\n", path, AcpiFormatException(rv));
return -1;
}
static int32_t
acpials_sensor_get_illuminance(device_t self)
{
/*
* The _ALI method returns the current ambient light
* illuminance reading in units of lux (lumen per
* square meter). The expected values range from about
* one lux (dark room) to 10000 lux (outdoor daylight).
*/
return acpials_sensor_get(self, "_ALI");
}
static int32_t
acpials_sensor_get_temperature(device_t self)
{
int32_t val;
/*
* The _ALT method returns the ambient light color
* temperature in degrees of Kelvin. Lower values
* indicate warmer light (yellow, red), whereas higher
* values imply a colder light (blue). According to
* the specification, the expected range is somewhere
* near 1500 K (candlelight) to 5500 K (sunlight).
*/
val = acpials_sensor_get(self, "_ALT");
return (val < 0) ? -1 : val * 1000000;
}
static int32_t
acpials_sensor_get_chromaticity(device_t self)
{
int32_t val;
/*
* The _ALC method returns the current ambient light
* chromaticity reading per the CIE Yxy color model.
* The encoding uses 32-bit integer value, where the
* x and y coordinates are stored in the high and low
* words, respectively. Valid values are specified to
* range from 0 (0x0000) to 1 (0x2710) per word.
*/
val = acpials_sensor_get(self, "_ALC");
if (val < 0)
return -1;
if (ACPI_ALS_CHROM_X(val) > ACPI_ALS_CHROM_MAX ||
ACPI_ALS_CHROM_Y(val) > ACPI_ALS_CHROM_MAX)
return -1;
return val;
}
static void
acpials_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct acpials_softc *sc = sme->sme_cookie;
mutex_enter(&sc->sc_mtx);
acpials_sensor_update(sc->sc_dev, edata);
mutex_exit(&sc->sc_mtx);
}
static void
acpials_sensor_update(device_t self, envsys_data_t *sensor)
{
int32_t val;
sensor->state = ENVSYS_SINVALID;
switch (sensor->units) {
case ENVSYS_STEMP:
val = acpials_sensor_get_temperature(self);
if (val < 0)
return;
sensor->state = ENVSYS_SVALID;
sensor->value_cur = val;
break;
case ENVSYS_INTEGER:
if (strcmp(sensor->desc, "illuminance") == 0) {
val = acpials_sensor_get_illuminance(self);
if (val < 0)
return;
sensor->state = ENVSYS_SVALID;
sensor->value_cur = val;
break;
}
if (strcmp(sensor->desc, "x-chromaticity") == 0) {
val = acpials_sensor_get_chromaticity(self);
if (val < 0)
return;
sensor->state = ENVSYS_SVALID;
val = ACPI_ALS_CHROM_X(val);
sensor->value_cur = ACPI_ALS_CHROM_TOPER(val);
break;
}
if (strcmp(sensor->desc, "y-chromaticity") == 0) {
val = acpials_sensor_get_chromaticity(self);
if (val < 0)
return;
sensor->state = ENVSYS_SVALID;
val = ACPI_ALS_CHROM_X(val);
sensor->value_cur = ACPI_ALS_CHROM_TOPER(val);
break;
}
}
}
static void
acpials_notify_handler(ACPI_HANDLE hdl, uint32_t evt, void *aux)
{
struct acpials_softc *sc;
envsys_data_t *sensor;
device_t self = aux;
size_t i;
sc = device_private(self);
switch (evt) {
case ACPI_ALS_NOTIFY_ILLUM:
sensor = &sc->sc_sensor[ACPI_ALS_SENSOR_ILLUM];
mutex_enter(&sc->sc_mtx);
acpials_sensor_update(self, sensor);
mutex_exit(&sc->sc_mtx);
break;
case ACPI_ALS_NOTIFY_TEMP:
i = ACPI_ALS_SENSOR_TEMP;
mutex_enter(&sc->sc_mtx);
while (i < __arraycount(sc->sc_sensor)) {
sensor = &sc->sc_sensor[i];
acpials_sensor_update(self, sensor);
i++;
}
mutex_exit(&sc->sc_mtx);
break;
case ACPI_ALS_NOTIFY_RESP: /* AE_SUPPORT */
break;
default:
aprint_debug_dev(self, "unknown notify 0x%02X\n", evt);
}
}
MODULE(MODULE_CLASS_DRIVER, acpials, NULL);
#ifdef _MODULE
#include "ioconf.c"
#endif
static int
acpials_modcmd(modcmd_t cmd, void *aux)
{
int rv = 0;
switch (cmd) {
case MODULE_CMD_INIT:
#ifdef _MODULE
rv = config_init_component(cfdriver_ioconf_acpials,
cfattach_ioconf_acpials, cfdata_ioconf_acpials);
#endif
break;
case MODULE_CMD_FINI:
#ifdef _MODULE
rv = config_fini_component(cfdriver_ioconf_acpials,
cfattach_ioconf_acpials, cfdata_ioconf_acpials);
#endif
break;
default:
rv = ENOTTY;
}
return rv;
}
/* $NetBSD$ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jukka Ruohonen Gregoire Sutre.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi_fan.c,v 1.6 2011/06/21 09:49:05 jruoho Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <dev/i2c/i2cvar.h>
#include <dev/i2c/isl29018reg.h>
#include <dev/sysmon/sysmonvar.h>
#define ISL_SENSOR_IR 0
#define ISL_SENSOR_ALS 1
#define ISL_SENSOR_PROX 2
#define ISL_SENSOR_COUNT 3
#define ISL_IR_NAME "infrared light"
#define ISL_ALS_NAME "ambient light"
#define ISL_PROX_NAME "proximity"
struct isl_softc {
device_t sc_dev;
i2c_tag_t sc_tag;
i2c_addr_t sc_addr;
uint8_t sc_resol;
uint16_t sc_range;
envsys_data_t sc_sensor[ISL_SENSOR_COUNT];
struct sysmon_envsys *sc_sme;
};
static int isl_match(device_t, cfdata_t, void *);
static void isl_attach(device_t, device_t, void *);
static int isl_detach(device_t, int);
static bool isl_init(device_t);
static bool isl_init_sensors(device_t);
static bool isl_read(device_t, uint8_t, uint8_t *);
static bool isl_read_ir(device_t, uint16_t *);
static bool isl_read_als(device_t, uint16_t *);
static bool isl_read_prox(device_t, uint16_t *);
static bool isl_read_sensor(device_t, uint8_t, uint16_t *);
static bool isl_write(device_t, uint8_t, uint8_t);
static bool isl_power(device_t, bool);
static void isl_refresh(struct sysmon_envsys *, envsys_data_t *);
static bool isl_suspend(device_t, const pmf_qual_t *);
static bool isl_resume(device_t, const pmf_qual_t *);
CFATTACH_DECL_NEW(isl, sizeof(struct isl_softc),
isl_match, isl_attach, isl_detach, NULL);
static int
isl_match(device_t parent, cfdata_t cf, void *aux)
{
struct i2c_attach_args *ia = aux;
if ((ia->ia_addr & ISL_ADDRMASK) != ISL_ADDR)
return 0;
return 1;
}
static void
isl_attach(device_t parent, device_t self, void *aux)
{
struct isl_softc *sc = device_private(self);
struct i2c_attach_args *ia = aux;
sc->sc_dev = self;
sc->sc_sme = NULL;
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
if (isl_init(self) != true) {
aprint_error(": failed to initialize device\n");
return;
}
if (isl_init_sensors(self) != true) {
aprint_error(": failed to initialize sensors\n");
return;
}
aprint_naive("\n");
aprint_normal(": ambient light sensor\n");
aprint_verbose_dev(self, "ISL29018, %u bit ADC resolution, "
"%u full scale lux range\n", sc->sc_resol, sc->sc_range);
(void)pmf_device_register(self, isl_suspend, isl_resume);
}
static int
isl_detach(device_t self, int flags)
{
struct isl_softc *sc = device_private(self);
(void)isl_power(self, false);
if (sc->sc_sme != NULL)
sysmon_envsys_unregister(sc->sc_sme);
return 0;
}
static bool
isl_init(device_t self)
{
struct isl_softc *sc = device_private(self);
uint8_t val;
if (isl_power(self, true) != true)
return false;
if (isl_read(self, ISL_REG_CMD2, &val) != true)
return false;
switch (__SHIFTOUT(val, ISL_CMD2_RANGE_MASK)) {
case ISL_CMD2_RANGE_1:
sc->sc_range = 1000;
break;
case ISL_CMD2_RANGE_2:
sc->sc_range = 4000;
break;
case ISL_CMD2_RANGE_3:
sc->sc_range = 16000;
break;
case ISL_CMD2_RANGE_4:
sc->sc_range = 64000;
break;
}
switch (__SHIFTOUT(val, ISL_CMD2_RESOL_MASK)) {
case ISL_CMD2_RESOL_4:
sc->sc_resol = 4;
break;
case ISL_CMD2_RESOL_8:
sc->sc_resol = 8;
break;
case ISL_CMD2_RESOL_12:
sc->sc_resol = 12;
break;
case ISL_CMD2_RESOL_16:
sc->sc_resol = 16;
break;
}
return true;
}
static bool
isl_init_sensors(device_t self)
{
struct isl_softc *sc = device_private(self);
envsys_data_t *sensor;
uint16_t val;
sc->sc_sme = sysmon_envsys_create();
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_flags = SME_POLL_ONLY;
sc->sc_sme->sme_refresh = isl_refresh;
sc->sc_sme->sme_name = device_xname(self);
if (isl_read_ir(self, &val) != false) {
sensor = &sc->sc_sensor[ISL_SENSOR_IR];
sensor->value_cur = val;
sensor->units = ENVSYS_INTEGER;
sensor->state = ENVSYS_SVALID;
(void)strlcpy(sensor->desc, ISL_IR_NAME, ENVSYS_DESCLEN);
(void)sysmon_envsys_sensor_attach(sc->sc_sme, sensor);
}
if (isl_read_als(self, &val) != false) {
sensor = &sc->sc_sensor[ISL_SENSOR_ALS];
sensor->value_cur = val;
sensor->units = ENVSYS_INTEGER;
sensor->state = ENVSYS_SVALID;
(void)strlcpy(sensor->desc, ISL_ALS_NAME, ENVSYS_DESCLEN);
(void)sysmon_envsys_sensor_attach(sc->sc_sme, sensor);
}
if (isl_read_prox(self, &val) != false) {
sensor = &sc->sc_sensor[ISL_SENSOR_PROX];
sensor->value_cur = val;
sensor->units = ENVSYS_INTEGER;
sensor->state = ENVSYS_SVALID;
(void)strlcpy(sensor->desc, ISL_PROX_NAME, ENVSYS_DESCLEN);
(void)sysmon_envsys_sensor_attach(sc->sc_sme, sensor);
}
if (sc->sc_sme->sme_nsensors == 0) {
sysmon_envsys_destroy(sc->sc_sme);
sc->sc_sme = NULL;
return false;
}
return true;
}
static bool
isl_read(device_t self, uint8_t cmd, uint8_t *valp)
{
struct isl_softc *sc = device_private(self);
uint8_t val;
if (iic_smbus_read_byte(sc->sc_tag, sc->sc_addr, cmd, &val, 0) != 0)
return false;
*valp = val;
return true;
}
static bool
isl_read_ir(device_t self, uint16_t *valp)
{
if (isl_read_sensor(self, ISL_CMD1_MODE_IRONCE, valp) != true)
return false;
return true;
}
static bool
isl_read_als(device_t self, uint16_t *valp)
{
struct isl_softc *sc = device_private(self);
uint16_t val;
if (isl_read_sensor(self, ISL_CMD1_MODE_ALSONCE, &val) != true)
return false;
/*
* The lux is calculated as: (k / 2^n) * data,
* where k is the range and n is the resolution.
*/
*valp = (val * sc->sc_range) >> sc->sc_resol;
return true;
}
static bool
isl_read_prox(device_t self, uint16_t *valp)
{
uint16_t ir, prox;
uint8_t mode, val;
/*
* Try to sense the proximity as IR from LED
* with ambient light rejection. The values
* range from -2^(n-1) to 2^(n-1).
*/
if (isl_read(self, ISL_REG_CMD2, &val) != true)
return false;
mode = __SHIFTOUT(val, ISL_CMD2_PROX_MASK);
mode |= ISL_CMD2_PROX_IRREJ;
val &= ~ISL_CMD2_PROX_MASK;
val |= __SHIFTIN(mode, ISL_CMD2_PROX_MASK);
if (isl_write(self, ISL_REG_CMD2, val) != true)
return false;
if (isl_read_sensor(self, ISL_CMD1_MODE_PROXONCE, &prox) != true)
return false;
if (isl_read_ir(self, &ir) != true)
return false;
*valp = (ir < prox) ? 0 : prox - ir;
return true;
}
static bool
isl_read_sensor(device_t self, uint8_t cmd, uint16_t *valp)
{
uint8_t lsb, mode, msb, val;
if (isl_read(self, ISL_REG_CMD1, &val) != true)
return false;
mode = __SHIFTOUT(val, ISL_CMD1_MODE_MASK);
mode |= cmd;
val &= ~ISL_CMD1_MODE_MASK;
val |= __SHIFTIN(mode, ISL_CMD1_MODE_MASK);
if (isl_write(self, ISL_REG_CMD1, val) != true)
return false;
if (isl_read(self, ISL_REG_DATA1, &lsb) != true)
return false;
if (isl_read(self, ISL_REG_DATA1, &msb) != true)
return false;
*valp = (msb << 8) | lsb;
return true;
}
static bool
isl_write(device_t self, uint8_t cmd, uint8_t val)
{
struct isl_softc *sc = device_private(self);
if (iic_smbus_write_byte(sc->sc_tag, sc->sc_addr, cmd, val, 0) != 0)
return false;
DELAY(90); /* Some delay is recommended. */
return true;
}
static bool
isl_power(device_t self, bool enable)
{
uint8_t mode, val;
if (isl_read(self, ISL_REG_CMD1, &val) != true)
return false;
mode = __SHIFTOUT(val, ISL_CMD1_MODE_MASK);
if (enable != false)
mode &= ~ISL_CMD1_MODE_POWERDOWN;
else
mode |= ISL_CMD1_MODE_POWERDOWN;
val &= ~ISL_CMD1_MODE_MASK;
val |= __SHIFTIN(mode, ISL_CMD1_MODE_MASK);
return isl_write(self, ISL_REG_CMD1, val);
}
static void
isl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
{
struct isl_softc *sc = sme->sme_cookie;
uint16_t val;
if (strcmp(edata->desc, ISL_IR_NAME) == 0) {
sc->sc_sensor[ISL_SENSOR_IR].state = ENVSYS_SINVALID;
if (isl_read_ir(sc->sc_dev, &val) != false) {
sc->sc_sensor[ISL_SENSOR_IR].value_cur = val;
sc->sc_sensor[ISL_SENSOR_IR].state = ENVSYS_SVALID;
}
}
if (strcmp(edata->desc, ISL_ALS_NAME) == 0) {
sc->sc_sensor[ISL_SENSOR_ALS].state = ENVSYS_SINVALID;
if (isl_read_als(sc->sc_dev, &val) != false) {
sc->sc_sensor[ISL_SENSOR_ALS].value_cur = val;
sc->sc_sensor[ISL_SENSOR_ALS].state = ENVSYS_SVALID;
}
}
if (strcmp(edata->desc, ISL_PROX_NAME) == 0) {
sc->sc_sensor[ISL_SENSOR_PROX].state = ENVSYS_SINVALID;
if (isl_read_prox(sc->sc_dev, &val) != false) {
sc->sc_sensor[ISL_SENSOR_PROX].value_cur = val;
sc->sc_sensor[ISL_SENSOR_PROX].state = ENVSYS_SVALID;
}
}
}
static bool
isl_suspend(device_t self, const pmf_qual_t *qual)
{
(void)isl_power(self, false);
return true;
}
static bool
isl_resume(device_t self, const pmf_qual_t *qual)
{
(void)isl_power(self, true);
return true;
}
/* $NetBSD$ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jukka Ruohonen Gregoire Sutre.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEV_I2C_ISL29018REG_H
#define _DEV_I2C_ISL29018REG_H
/*
* Derived from the following:
*
* Intersil: ISL29018, Data Sheet,
* February 11, 2010. FN6619.1.
*/
#define ISL_ADDRMASK 0x7C
#define ISL_ADDR 0x44
#define ISL_REG_CMD1 0x00
#define ISL_REG_CMD2 0x01
#define ISL_REG_DATA1 0x02
#define ISL_REG_DATA2 0x03
#define ISL_CMD1_INTRP_MASK __BITS(0, 1)
#define ISL_CMD1_INTRP_CYCLE_1 0x00
#define ISL_CMD1_INTRP_CYCLE_4 0x01
#define ISL_CMD1_INTRP_CYCLE_8 0x02
#define ISL_CMD1_INTRP_CYCLE_16 0x03
#define ISL_CMD1_INTRF_MASK __BIT(2)
#define ISL_CMD1_INTRF_CLEARED 0x00
#define ISL_CMD1_INTRF_TRIGGER 0x01
#define ISL_CMD1_MODE_MASK __BITS(5, 7)
#define ISL_CMD1_MODE_POWERDOWN 0x00
#define ISL_CMD1_MODE_ALSONCE 0x01
#define ISL_CMD1_MODE_IRONCE 0x02
#define ISL_CMD1_MODE_PROXONCE 0x03
#define ISL_CMD1_MODE_ALSCONT 0x05
#define ISL_CMD1_MODE_IRCONT 0x06
#define ISL_CMD1_MODE_PROXCONT 0x07
#define ISL_CMD2_RANGE_MASK __BITS(0, 1)
#define ISL_CMD2_RANGE_1 0x00
#define ISL_CMD2_RANGE_2 0x01
#define ISL_CMD2_RANGE_3 0x02
#define ISL_CMD2_RANGE_4 0x03
#define ISL_CMD2_RESOL_MASK __BITS(2, 3)
#define ISL_CMD2_RESOL_16 0x00
#define ISL_CMD2_RESOL_12 0x01
#define ISL_CMD2_RESOL_8 0x02
#define ISL_CMD2_RESOL_4 0x03
#define ISL_CMD2_AMPL_MASK __BITS(4, 5)
#define ISL_CMD2_AMPL_12 0x00
#define ISL_CMD2_AMPL_25 0x01
#define ISL_CMD2_AMPL_50 0x02
#define ISL_CMD2_AMPL_100 0x03
#define ISL_CMD2_FREQ_MASK __BIT(6)
#define ISL_CMD2_FREQ_DC 0x00
#define ISL_CMD2_FREQ_360 0x01
#define ISL_CMD2_PROX_MASK __BIT(7)
#define ISL_CMD2_PROX_AMBIENT 0x00
#define ISL_CMD2_PROX_IRREJ 0x01
#endif /* !_DEV_I2C_ISL29018REG_H */
Home |
Main Index |
Thread Index |
Old Index