Skip to content

Commit

Permalink
drivers: apds9960: use interrupt output for sample
Browse files Browse the repository at this point in the history
This patch changes the behavior of the sensor. The sensor
will remain in sleep mode after initialization and will only
run the measurements once when sample_fetch is called.
This optimizes the power consumption of the sensor as it
stays in sleep mode most of the time.

Signed-off-by: Johann Fischer <j.fischer@phytec.de>
  • Loading branch information
jfischer-no authored and MaureenHelm committed Sep 21, 2018
1 parent 9c3d773 commit 963f97d
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 17 deletions.
2 changes: 2 additions & 0 deletions boards/arm/reel_board/dts.fixup
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@

#define CONFIG_APDS9960_DRV_NAME NORDIC_NRF_I2C_40003000_AVAGO_APDS9960_29_LABEL
#define CONFIG_APDS9960_I2C_DEV_NAME NORDIC_NRF_I2C_40003000_AVAGO_APDS9960_29_BUS_NAME
#define CONFIG_APDS9960_GPIO_DEV_NAME NORDIC_NRF_I2C_40003000_AVAGO_APDS9960_29_INT_GPIOS_CONTROLLER
#define CONFIG_APDS9960_GPIO_PIN_NUM NORDIC_NRF_I2C_40003000_AVAGO_APDS9960_29_INT_GPIOS_PIN
18 changes: 18 additions & 0 deletions drivers/sensor/apds9960/Kconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#
# Copyright (c) 2017 Intel Corporation
# Copyright (c) 2018 Phytec Messtechnik GmbH
#
# SPDX-License-Identifier: Apache-2.0
#
Expand Down Expand Up @@ -29,4 +30,21 @@ config APDS9960_DRV_NAME

endif # !HAS_DTS_I2C_DEVICE

if !HAS_DTS_GPIO_DEVICE

config APDS9960_GPIO_DEV_NAME
string "GPIO device"
default "GPIO_0"
help
The GPIO device's name where the APDS9960 interrupt pin is connected.

config APDS9960_GPIO_PIN_NUM
int "Interrupt GPIO pin number"
default 0
help
The GPIO pin number receiving the interrupt signal from the
APDS9960 sensor.

endif # !HAS_DTS_GPIO_DEVICE

endif # APDS9960
120 changes: 103 additions & 17 deletions drivers/sensor/apds9960/apds9960.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,70 @@

#include "apds9960.h"

static void apds9960_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct apds9960_data *drv_data =
CONTAINER_OF(cb, struct apds9960_data, gpio_cb);

gpio_pin_disable_callback(dev, CONFIG_APDS9960_GPIO_PIN_NUM);

k_sem_give(&drv_data->data_sem);
}

static int apds9960_sample_fetch(struct device *dev, enum sensor_channel chan)
{
struct apds9960_data *data = dev->driver_data;
u8_t status;

__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);

/* Read CRGB registers */
if (i2c_burst_read(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_CDATAL_REG,
(u8_t *)&data->sample_crgb,
sizeof(data->sample_crgb))) {
SYS_LOG_DBG("");
gpio_pin_enable_callback(data->gpio,
CONFIG_APDS9960_GPIO_PIN_NUM);

if (i2c_reg_update_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_ENABLE_REG,
APDS9960_ENABLE_PON | APDS9960_ENABLE_AIEN,
APDS9960_ENABLE_PON | APDS9960_ENABLE_AIEN)) {
SYS_LOG_ERR("Power on bit not set.");
return -EIO;
}

k_sem_take(&data->data_sem, K_FOREVER);

if (i2c_reg_read_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_PDATA_REG, &data->pdata)) {
APDS9960_STATUS_REG, &status)) {
return -EIO;
}

SYS_LOG_DBG("status: 0x%x", status);
if (status & APDS9960_STATUS_PINT) {
if (i2c_reg_read_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_PDATA_REG, &data->pdata)) {
return -EIO;
}
}

if (status & APDS9960_STATUS_AINT) {
if (i2c_burst_read(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_CDATAL_REG,
(u8_t *)&data->sample_crgb,
sizeof(data->sample_crgb))) {
return -EIO;
}

}

if (i2c_reg_update_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_ENABLE_REG,
APDS9960_ENABLE_PON,
0)) {
return -EIO;
}

if (i2c_reg_write_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_AICLEAR_REG, 0)) {
return -EIO;
}

Expand Down Expand Up @@ -237,6 +285,13 @@ static int apds9960_sensor_setup(struct device *dev)
return -EIO;
}

if (i2c_reg_write_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_CONFIG3_REG,
APDS9960_CONFIG3_SAI)) {
SYS_LOG_ERR("Configuration Register Three not set");
return -EIO;
}

if (i2c_reg_write_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_PERS_REG,
APDS9960_DEFAULT_PERS)) {
Expand All @@ -254,25 +309,46 @@ static int apds9960_sensor_setup(struct device *dev)
return -EIO;
}

if (i2c_reg_update_byte(data->i2c, APDS9960_I2C_ADDRESS,
APDS9960_ENABLE_REG,
APDS9960_ENABLE_PON, APDS9960_ENABLE_PON)) {
SYS_LOG_ERR("Power on bit not set");
return 0;
}

static int apds9960_init_interrupt(struct device *dev)
{
struct apds9960_data *drv_data = dev->driver_data;

/* setup gpio interrupt */
drv_data->gpio = device_get_binding(CONFIG_APDS9960_GPIO_DEV_NAME);
if (drv_data->gpio == NULL) {
SYS_LOG_ERR("Failed to get pointer to %s device!",
CONFIG_APDS9960_GPIO_DEV_NAME);
return -EINVAL;
}

gpio_pin_configure(drv_data->gpio, CONFIG_APDS9960_GPIO_PIN_NUM,
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE |
GPIO_PUD_PULL_UP);

gpio_init_callback(&drv_data->gpio_cb,
apds9960_gpio_callback,
BIT(CONFIG_APDS9960_GPIO_PIN_NUM));

if (gpio_add_callback(drv_data->gpio, &drv_data->gpio_cb) < 0) {
SYS_LOG_DBG("Failed to set gpio callback!");
return -EIO;
}

k_sem_init(&drv_data->data_sem, 0, UINT_MAX);

return 0;
}

static const struct sensor_driver_api apds9960_driver_api = {
.sample_fetch = &apds9960_sample_fetch,
.channel_get = &apds9960_channel_get,
};

static int apds9960_init(struct device *dev)
{
struct apds9960_data *data = dev->driver_data;

/* Initialize time 5.7ms */
k_sleep(6);
data->i2c = device_get_binding(CONFIG_APDS9960_I2C_DEV_NAME);

if (data->i2c == NULL) {
Expand All @@ -286,11 +362,21 @@ static int apds9960_init(struct device *dev)

apds9960_sensor_setup(dev);

if (apds9960_init_interrupt(dev) < 0) {
SYS_LOG_ERR("Failed to initialize interrupt!");
return -EIO;
}

return 0;
}

static const struct sensor_driver_api apds9960_driver_api = {
.sample_fetch = &apds9960_sample_fetch,
.channel_get = &apds9960_channel_get,
};

static struct apds9960_data apds9960_data;

DEVICE_AND_API_INIT(apds9960, CONFIG_APDS9960_DRV_NAME, &apds9960_init,
&apds9960_data, NULL, POST_KERNEL,
CONFIG_SENSOR_INIT_PRIORITY, &apds9960_driver_api);
&apds9960_data, NULL, POST_KERNEL,
CONFIG_SENSOR_INIT_PRIORITY, &apds9960_driver_api);
8 changes: 8 additions & 0 deletions drivers/sensor/apds9960/apds9960.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#ifndef ZEPHYR_DRIVERS_SENSOR_APDS9960_APDS9960_H_
#define ZEPHYR_DRIVERS_SENSOR_APDS9960_APDS9960_H_

#include <gpio.h>

#define APDS9960_I2C_ADDRESS 0x39

#define APDS9960_ENABLE_REG 0x80
Expand Down Expand Up @@ -210,8 +212,14 @@

struct apds9960_data {
struct device *i2c;
struct device *gpio;
struct gpio_callback gpio_cb;
struct k_work work;
struct device *dev;
u16_t sample_crgb[4];
u8_t pdata;

struct k_sem data_sem;
};

#define SYS_LOG_DOMAIN "APDS9960"
Expand Down

0 comments on commit 963f97d

Please sign in to comment.