diff --git a/boards/arm/nrf52_pca20020/nrf52_pca20020.dts b/boards/arm/nrf52_pca20020/nrf52_pca20020.dts index 350158facde..56593848655 100644 --- a/boards/arm/nrf52_pca20020/nrf52_pca20020.dts +++ b/boards/arm/nrf52_pca20020/nrf52_pca20020.dts @@ -121,9 +121,9 @@ compatible = "ams,ccs811"; reg = <0x5a>; label = "CCS811"; - irq-gpios = <&gpio0 22 0>; - reset-gpios = <&sx1509b 11 0>; - wake-gpios = <&sx1509b 12 0>; + irq-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; + reset-gpios = <&sx1509b 11 GPIO_ACTIVE_LOW>; + wake-gpios = <&sx1509b 12 GPIO_ACTIVE_LOW>; }; }; diff --git a/drivers/sensor/ccs811/ccs811.c b/drivers/sensor/ccs811/ccs811.c index 7be901d3e60..086f4e77c33 100644 --- a/drivers/sensor/ccs811/ccs811.c +++ b/drivers/sensor/ccs811/ccs811.c @@ -17,13 +17,15 @@ #include "ccs811.h" +#define WAKE_PIN DT_INST_0_AMS_CCS811_WAKE_GPIOS_PIN +#define RESET_PIN DT_INST_0_AMS_CCS811_RESET_GPIOS_PIN + LOG_MODULE_REGISTER(CCS811, CONFIG_SENSOR_LOG_LEVEL); #ifdef DT_INST_0_AMS_CCS811_WAKE_GPIOS_CONTROLLER static void set_wake(struct ccs811_data *drv_data, bool enable) { - /* Always active-low */ - gpio_pin_write(drv_data->wake_gpio, DT_INST_0_AMS_CCS811_WAKE_GPIOS_PIN, !enable); + gpio_pin_set(drv_data->wake_gpio, WAKE_PIN, enable); if (enable) { k_busy_wait(50); /* t_WAKE = 50 us */ } else { @@ -455,8 +457,9 @@ static int ccs811_init(struct device *dev) * any I2C transfer. If it has been tied to GND by * default, skip this part. */ - gpio_pin_configure(drv_data->wake_gpio, DT_INST_0_AMS_CCS811_WAKE_GPIOS_PIN, - GPIO_DIR_OUT); + gpio_pin_configure(drv_data->wake_gpio, WAKE_PIN, + GPIO_OUTPUT_INACTIVE + | DT_INST_0_AMS_CCS811_WAKE_GPIOS_FLAGS); set_wake(drv_data, true); k_sleep(1); @@ -468,16 +471,16 @@ static int ccs811_init(struct device *dev) DT_INST_0_AMS_CCS811_RESET_GPIOS_CONTROLLER); return -EINVAL; } - gpio_pin_configure(drv_data->reset_gpio, DT_INST_0_AMS_CCS811_RESET_GPIOS_PIN, - GPIO_DIR_OUT); - gpio_pin_write(drv_data->reset_gpio, DT_INST_0_AMS_CCS811_RESET_GPIOS_PIN, 1); + gpio_pin_configure(drv_data->reset_gpio, RESET_PIN, + GPIO_OUTPUT_ACTIVE + | DT_INST_0_AMS_CCS811_RESET_GPIOS_FLAGS); k_sleep(1); #endif #ifdef DT_INST_0_AMS_CCS811_IRQ_GPIOS_CONTROLLER - drv_data->int_gpio = device_get_binding(DT_INST_0_AMS_CCS811_IRQ_GPIOS_CONTROLLER); - if (drv_data->int_gpio == NULL) { + drv_data->irq_gpio = device_get_binding(DT_INST_0_AMS_CCS811_IRQ_GPIOS_CONTROLLER); + if (drv_data->irq_gpio == NULL) { LOG_ERR("Failed to get pointer to INT device: %s", DT_INST_0_AMS_CCS811_IRQ_GPIOS_CONTROLLER); return -EINVAL; @@ -488,10 +491,10 @@ static int ccs811_init(struct device *dev) * and validating any errors or configuration inconsistencies * after a reset that left the device running. */ -#ifdef DT_INST_0_AMS_CCS811_RESET_GPIOS_PIN - gpio_pin_write(drv_data->reset_gpio, DT_INST_0_AMS_CCS811_RESET_GPIOS_PIN, 0); +#ifdef DT_INST_0_AMS_CCS811_RESET_GPIOS_CONTROLLER + gpio_pin_set(drv_data->reset_gpio, RESET_PIN, 1); k_busy_wait(15); /* t_RESET */ - gpio_pin_write(drv_data->reset_gpio, DT_INST_0_AMS_CCS811_RESET_GPIOS_PIN, 1); + gpio_pin_set(drv_data->reset_gpio, RESET_PIN, 0); #else { static u8_t const reset_seq[] = { diff --git a/drivers/sensor/ccs811/ccs811.h b/drivers/sensor/ccs811/ccs811.h index 553a06bb1c4..05ad559a1ae 100644 --- a/drivers/sensor/ccs811/ccs811.h +++ b/drivers/sensor/ccs811/ccs811.h @@ -50,8 +50,10 @@ struct ccs811_data { struct device *i2c; #ifdef DT_INST_0_AMS_CCS811_IRQ_GPIOS_CONTROLLER - struct device *int_gpio; + struct device *irq_gpio; #ifdef CONFIG_CCS811_TRIGGER + struct device *dev; + /* * DATARDY is configured through SENSOR_CHAN_ALL. * THRESH would be configured through SENSOR_CHAN_CO2. @@ -65,7 +67,6 @@ struct ccs811_data { struct k_thread thread; #elif defined(CONFIG_CCS811_TRIGGER_GLOBAL_THREAD) struct k_work work; - struct device *dev; #endif u16_t co2_l2m; u16_t co2_m2h; diff --git a/drivers/sensor/ccs811/ccs811_trigger.c b/drivers/sensor/ccs811/ccs811_trigger.c index 54cfe229d59..cf95a2d9c70 100644 --- a/drivers/sensor/ccs811/ccs811_trigger.c +++ b/drivers/sensor/ccs811/ccs811_trigger.c @@ -11,6 +11,8 @@ #include LOG_MODULE_DECLARE(CCS811); +#define IRQ_PIN DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN + int ccs811_attr_set(struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, @@ -41,40 +43,57 @@ int ccs811_attr_set(struct device *dev, return rc; } +static inline void setup_irq(struct device *dev, + bool enable) +{ + struct ccs811_data *data = dev->driver_data; + unsigned int flags = enable + ? GPIO_INT_LEVEL_ACTIVE + : GPIO_INT_DISABLE; + + gpio_pin_interrupt_configure(data->irq_gpio, IRQ_PIN, flags); +} + +static inline void handle_irq(struct device *dev) +{ + struct ccs811_data *data = dev->driver_data; + + setup_irq(dev, false); + +#if defined(CONFIG_CCS811_TRIGGER_OWN_THREAD) + k_sem_give(&data->gpio_sem); +#elif defined(CONFIG_CCS811_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} + +static void process_irq(struct device *dev) +{ + struct ccs811_data *data = dev->driver_data; + + if (data->handler != NULL) { + data->handler(dev, &data->trigger); + } + + if (data->handler != NULL) { + setup_irq(dev, true); + } +} + static void gpio_callback(struct device *dev, struct gpio_callback *cb, u32_t pins) { - struct ccs811_data *drv_data = + struct ccs811_data *data = CONTAINER_OF(cb, struct ccs811_data, gpio_cb); ARG_UNUSED(pins); - gpio_pin_disable_callback(dev, DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN); - -#if defined(CONFIG_CCS811_TRIGGER_OWN_THREAD) - k_sem_give(&drv_data->gpio_sem); -#elif defined(CONFIG_CCS811_TRIGGER_GLOBAL_THREAD) - k_work_submit(&drv_data->work); -#else -#error Unhandled trigger configuration -#endif -} - -static void thread_cb(void *arg) -{ - struct device *dev = arg; - struct ccs811_data *drv_data = dev->driver_data; - - if (drv_data->handler != NULL) { - drv_data->handler(dev, &drv_data->trigger); - } - - gpio_pin_enable_callback(drv_data->int_gpio, DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN); + handle_irq(data->dev); } #ifdef CONFIG_CCS811_TRIGGER_OWN_THREAD -static void datardy_thread(int dev_ptr, int unused) +static void irq_thread(int dev_ptr, int unused) { struct device *dev = INT_TO_POINTER(dev_ptr); struct ccs811_data *drv_data = dev->driver_data; @@ -83,16 +102,15 @@ static void datardy_thread(int dev_ptr, int unused) while (1) { k_sem_take(&drv_data->gpio_sem, K_FOREVER); - thread_cb(dev); + process_irq(dev); } } #elif defined(CONFIG_CCS811_TRIGGER_GLOBAL_THREAD) static void work_cb(struct k_work *work) { - struct ccs811_data *drv_data = - CONTAINER_OF(work, struct ccs811_data, work); + struct ccs811_data *data = CONTAINER_OF(work, struct ccs811_data, work); - thread_cb(drv_data->dev); + process_irq(data->dev); } #else #error Unhandled trigger configuration @@ -107,7 +125,13 @@ int ccs811_trigger_set(struct device *dev, int rc; LOG_DBG("CCS811 trigger set"); - gpio_pin_disable_callback(drv_data->int_gpio, DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN); + setup_irq(dev, false); + + drv_data->handler = handler; + if (handler == NULL) { + return 0; + } + if (trig->type == SENSOR_TRIG_DATA_READY) { rc = ccs811_mutate_meas_mode(dev, CCS811_MODE_DATARDY, CCS811_MODE_THRESH); @@ -128,11 +152,14 @@ int ccs811_trigger_set(struct device *dev, } if (rc == 0) { - drv_data->handler = handler; drv_data->trigger = *trig; - gpio_pin_enable_callback(drv_data->int_gpio, - DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN); + setup_irq(dev, true); + + if (gpio_pin_get(drv_data->irq_gpio, IRQ_PIN) > 0) { + handle_irq(dev); + } } else { + drv_data->handler = NULL; (void)ccs811_mutate_meas_mode(dev, 0, drdy_thresh); } @@ -143,18 +170,14 @@ int ccs811_init_interrupt(struct device *dev) { struct ccs811_data *drv_data = dev->driver_data; -#ifndef DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN - return -EINVAL; -#endif - gpio_pin_configure(drv_data->int_gpio, DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN, - GPIO_DIR_IN | GPIO_INT | GPIO_INT_LEVEL | - GPIO_INT_ACTIVE_LOW | GPIO_PUD_PULL_UP | - GPIO_INT_DEBOUNCE); + drv_data->dev = dev; - gpio_init_callback(&drv_data->gpio_cb, gpio_callback, - BIT(DT_INST_0_AMS_CCS811_IRQ_GPIOS_PIN)); + gpio_pin_configure(drv_data->irq_gpio, IRQ_PIN, + GPIO_INPUT | DT_INST_0_AMS_CCS811_IRQ_GPIOS_FLAGS); - if (gpio_add_callback(drv_data->int_gpio, &drv_data->gpio_cb) < 0) { + gpio_init_callback(&drv_data->gpio_cb, gpio_callback, BIT(IRQ_PIN)); + + if (gpio_add_callback(drv_data->irq_gpio, &drv_data->gpio_cb) < 0) { LOG_DBG("Failed to set gpio callback!"); return -EIO; } @@ -164,12 +187,11 @@ int ccs811_init_interrupt(struct device *dev) k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_CCS811_THREAD_STACK_SIZE, - (k_thread_entry_t)datardy_thread, dev, + (k_thread_entry_t)irq_thread, dev, 0, NULL, K_PRIO_COOP(CONFIG_CCS811_THREAD_PRIORITY), 0, 0); #elif defined(CONFIG_CCS811_TRIGGER_GLOBAL_THREAD) drv_data->work.handler = work_cb; - drv_data->dev = dev; #else #error Unhandled trigger configuration #endif diff --git a/dts/bindings/sensor/ams,ccs811.yaml b/dts/bindings/sensor/ams,ccs811.yaml index 8c4c3b0dde1..4b5aa5d4588 100644 --- a/dts/bindings/sensor/ams,ccs811.yaml +++ b/dts/bindings/sensor/ams,ccs811.yaml @@ -11,14 +11,21 @@ properties: wake-gpios: type: phandle-array required: false - description: WAKEn pin + description: | + The WAKEn pin is asserted to communicate with the sensor. The + sensor receives this as an active-low signal. reset-gpios: type: phandle-array required: false - description: RESETn pin + description: | + The RESETn pin is asserted to disable the sensor causing a hard + reset. The sensor receives this as an active-low signal. irq-gpios: type: phandle-array required: false - description: INTn pin + description: | + The INTn pin signals that a new reading is available. The + sensor generates an active-low level signal which remains + asserted until the data is read. diff --git a/samples/sensor/ccs811/boards/nrf51_ble400.overlay b/samples/sensor/ccs811/boards/nrf51_ble400.overlay index 6ccee9f9bdc..8eebdd077c8 100644 --- a/samples/sensor/ccs811/boards/nrf51_ble400.overlay +++ b/samples/sensor/ccs811/boards/nrf51_ble400.overlay @@ -14,8 +14,8 @@ compatible = "ams,ccs811"; reg = <0x5b>; label = "CCS811"; - irq-gpios = <&gpio0 2 GPIO_INT_ACTIVE_LOW>; - wake-gpios = <&gpio0 5 GPIO_INT_ACTIVE_LOW>; - reset-gpios = <&gpio0 6 GPIO_INT_ACTIVE_LOW>; + irq-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + wake-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; }; };