gpio: Improve the public API to handle multi callbacks

Many sub-systems might require to set a callback on different pins.
Thus enabling it via changing the API.

It is also possible to retrieve private-data in the callback handler
using CONTAINER_OF() macro (include/misc/util.h).

Former API is still available, and is emulated through the new one.
Using both should not be a problem as it's using new API calls.
However, it's now better to start using the new API.

Change-Id: Id16594202905976cc524775d1cd3592b54a84514
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Tomasz Bursztyka 2016-03-23 12:01:06 +01:00 committed by Anas Nashif
commit fea1c49ba2
22 changed files with 537 additions and 224 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Intel Corporation.
* Copyright (c) 2015-2016 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,6 +21,14 @@
#ifndef __GPIO_H__
#define __GPIO_H__
#include <misc/__assert.h>
#include <misc/slist.h>
#include <stdint.h>
#include <stddef.h>
#include <device.h>
/**
* @brief GPIO Driver APIs
* @defgroup gpio_interface GPIO Driver APIs
@ -36,10 +44,6 @@ extern "C" {
#define GPIO_ACCESS_BY_PORT 1
/** @endcond */
#include <stdint.h>
#include <stddef.h>
#include <device.h>
/** GPIO pin to be input. */
#define GPIO_DIR_IN (0 << 0)
@ -126,9 +130,59 @@ extern "C" {
*
* @param port Device struct for the GPIO device.
* @param pin The pin that triggers the callback.
*
* Note: This is the former callback signature used to set a unique
* callback (API v1.0) through gpio_set_callback(). The new
* struct gpio_callback below is now the preferred way.
*/
typedef void (*gpio_callback_t)(struct device *port, uint32_t pin);
struct gpio_callback;
/**
* @brief Define the application callback handler function signature
*
* @param port Device struct for the GPIO device.
* @param cb Original struct gpio_callback owning this handler
* @param pins Mask of pins that triggers the callback handler
*
* Note: cb pointer can be used to retrieve private data through
* CONTAINER_OF() if original struct gpio_callback is stored in
* another private structure.
*/
typedef void (*gpio_callback_handler_t)(struct device *port,
struct gpio_callback *cb,
uint32_t pins);
/**
* @brief GPIO callback structure
*
* Used to register a callback in the driver instance callback list.
* As many callbacks as needed can be added as long as each of them
* are unique pointers of struct gpio_callback.
* Beware such structure should not be allocated on stack.
*
* Note: To help setting it, see gpio_init_callback() below
*/
struct gpio_callback {
/** This is meant to be used in the driver and the user should not
* mess with it (see drivers/gpio/gpio_utils.h)
*/
sys_snode_t node;
/** Actual callback function being called when relevant. */
gpio_callback_handler_t handler;
/** A mask of pins the callback is interested in, if 0 the callback
* will never be called. Such pin_mask can be modified whenever
* necessary by the owner, and thus will affect the handler being
* called or not. The selected pins must be configured to trigger
* an interrupt.
*/
uint32_t pin_mask;
};
/**
* @cond INTERNAL_HIDDEN
*
@ -142,8 +196,9 @@ typedef int (*gpio_write_t)(struct device *port, int access_op,
uint32_t pin, uint32_t value);
typedef int (*gpio_read_t)(struct device *port, int access_op,
uint32_t pin, uint32_t *value);
typedef int (*gpio_set_callback_t)(struct device *port,
gpio_callback_t callback);
typedef int (*gpio_manage_callback_t)(struct device *port,
struct gpio_callback *callback,
bool set);
typedef int (*gpio_enable_callback_t)(struct device *port,
int access_op,
uint32_t pin);
@ -155,7 +210,7 @@ struct gpio_driver_api {
gpio_config_t config;
gpio_write_t write;
gpio_read_t read;
gpio_set_callback_t set_callback;
gpio_manage_callback_t manage_callback;
gpio_enable_callback_t enable_callback;
gpio_disable_callback_t disable_callback;
};
@ -168,7 +223,6 @@ struct gpio_driver_api {
* @param port Pointer to device structure for the driver instance.
* @param pin Pin number to configure.
* @param flags Flags for pin configuration. IN/OUT, interrupt ...
*
*/
static inline int gpio_pin_configure(struct device *port, uint8_t pin,
int flags)
@ -192,7 +246,6 @@ static inline int gpio_pin_write(struct device *port, uint32_t pin,
api = (struct gpio_driver_api *) port->driver_api;
return api->write(port, GPIO_ACCESS_BY_PIN, pin, value);
}
/**
@ -208,27 +261,85 @@ static inline int gpio_pin_read(struct device *port, uint32_t pin,
api = (struct gpio_driver_api *) port->driver_api;
return api->read(port, GPIO_ACCESS_BY_PIN, pin, value);
}
/**
* @brief Set the application's callback function.
* @brief Former way of setting the application's callback.
* @param port Pointer to the device structure for the driver instance.
* @param callback Application's callback function.
* @param callback Application's callback (or NULL to unset).
*
* Note: This function sets a unique callback for the driver instance,
* i.e. another call to this function will overwrite it. This is
* the old way of doing things (API v1.0) and should be replaced
* by gpio_add_callback() and gpio_remove_callback().
* Using this function will not collide with the new ones.
*/
static inline int gpio_set_callback(struct device *port,
gpio_callback_t callback)
int gpio_set_callback(struct device *port, gpio_callback_t callback);
/**
* @brief Helper to initialize a struct gpio_callback properly
* @param callback A valid Application's callback structure pointer.
* @param handler A valid handler function pointer.
* @param pin_mask A bit mask of relevant pins for the handler
*/
static inline void gpio_init_callback(struct gpio_callback *callback,
gpio_callback_handler_t handler,
uint32_t pin_mask)
{
__ASSERT(callback, "Callback pointer should not be NULL");
__ASSERT(handler, "Callback handler pointer should not be NULL");
callback->handler = handler;
callback->pin_mask = pin_mask;
}
/**
* @brief Add an application callback.
* @param port Pointer to the device structure for the driver instance.
* @param callback A valid Application's callback structure pointer.
*
* Note: enables to add as many callback as needed on the same port.
* This is the preferred way and is replacing gpio_set_callback().
*/
static inline int gpio_add_callback(struct device *port,
struct gpio_callback *callback)
{
struct gpio_driver_api *api;
__ASSERT(callback, "Callback pointer should not be NULL");
api = (struct gpio_driver_api *) port->driver_api;
return api->set_callback(port, callback);
return api->manage_callback(port, callback, true);
}
/**
* @brief Enable the callback function for a single pin.
* @brief Remove an application callback.
* @param port Pointer to the device structure for the driver instance.
* @param callback A valid application's callback structure pointer.
*
* Note: enables to remove as many callacks as added through
* gpio_add_callback(). This is the preferred way and it's
* replacing gpio_set_callback() with a NULL pointer as a callback.
*/
static inline int gpio_remove_callback(struct device *port,
struct gpio_callback *callback)
{
struct gpio_driver_api *api;
__ASSERT(callback, "Callback pointer should not be NULL");
api = (struct gpio_driver_api *) port->driver_api;
return api->manage_callback(port, callback, false);
}
/**
* @brief Enable callback(s) for a single pin.
* @param port Pointer to the device structure for the driver instance.
* @param pin Pin number where the callback function is enabled.
*
* Note: Depending on the driver implementation, this function will enable
* the pin to trigger an interruption. So as a semantic detail, if no
* callback is registered, of course none will be called.
*/
static inline int gpio_pin_enable_callback(struct device *port, uint32_t pin)
{
@ -236,11 +347,10 @@ static inline int gpio_pin_enable_callback(struct device *port, uint32_t pin)
api = (struct gpio_driver_api *) port->driver_api;
return api->enable_callback(port, GPIO_ACCESS_BY_PIN, pin);
}
/**
* @brief Disable the callback function for a single pin.
* @brief Disable callback(s) for a single pin.
* @param port Pointer to the device structure for the driver instance.
* @param pin Pin number where the callback function is disabled.
*/
@ -252,10 +362,9 @@ static inline int gpio_pin_disable_callback(struct device *port, uint32_t pin)
return api->disable_callback(port, GPIO_ACCESS_BY_PIN, pin);
}
/**
* @brief Configure all the pins in the port.
* List out all flags on the detailed description.
* @brief Configure all the pins the same way in the port.
* List out all flags on the detailed description.
*
* @param port Pointer to the device structure for the driver instance.
* @param flags Flags for the port configuration. IN/OUT, interrupt ...
@ -279,7 +388,6 @@ static inline int gpio_port_write(struct device *port, uint32_t value)
api = (struct gpio_driver_api *) port->driver_api;
return api->write(port, GPIO_ACCESS_BY_PORT, 0, value);
}
/**
@ -293,12 +401,16 @@ static inline int gpio_port_read(struct device *port, uint32_t *value)
api = (struct gpio_driver_api *) port->driver_api;
return api->read(port, GPIO_ACCESS_BY_PORT, 0, value);
}
/**
* @brief Enable port callback.
* @brief Enable callback(s) for the port.
* @param port Pointer to the device structure for the driver instance.
*
* Note: Depending on the driver implementation, this function will enable
* the port to trigger an interruption on all pins, as long as these
* are configured properly. So as a semantic detail, if no callback
* is registered, of course none will be called.
*/
static inline int gpio_port_enable_callback(struct device *port)
{
@ -306,11 +418,10 @@ static inline int gpio_port_enable_callback(struct device *port)
api = (struct gpio_driver_api *) port->driver_api;
return api->enable_callback(port, GPIO_ACCESS_BY_PORT, 0);
}
/**
* @brief Disable the callback function for the port.
* @brief Disable callback(s) for the port.
* @param port Pointer to the device structure for the driver instance.
*/
static inline int gpio_port_disable_callback(struct device *port)