gpio: Introduce mraa_gpio_init_by_name API
This commit introduces mraa_gpio_init_by_name API for initializing a GPIO by its line name provided by the kernel. This feature depends on the GPIO chardev support and also the line names present in devicetree or board files. Accessing GPIO using its line name, removes the dependency from MRAA specific pin mapping and provides a cleaner way to access GPIOs. This will solve the issue created by an external gpiochip probing before the SoC's internal gpio controller and thereby making the MRAA pin mapping wrong. Currently, this API only supports initializing a single GPIO at a time. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
This commit is contained in:
committed by
Manivannan Sadhasivam
parent
111e6be8f7
commit
0a12c5a017
@@ -124,6 +124,14 @@ typedef mraa_gpio_event* mraa_gpio_events_t;
|
||||
*/
|
||||
mraa_gpio_context mraa_gpio_init(int pin);
|
||||
|
||||
/**
|
||||
* Initialise gpio_context, based on gpio line name
|
||||
*
|
||||
* @param name GPIO line name, i.e GPIO-A
|
||||
* @returns gpio context or NULL
|
||||
*/
|
||||
mraa_gpio_context mraa_gpio_init_by_name(char* name);
|
||||
|
||||
/**
|
||||
* Initialise gpio_context, based on board number, for multiple pins (can be one).
|
||||
*
|
||||
|
||||
@@ -64,6 +64,7 @@ mraa_boolean_t mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo);
|
||||
mraa_boolean_t mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo);
|
||||
|
||||
int mraa_get_number_of_gpio_chips();
|
||||
int mraa_get_chip_infos(mraa_gpiod_chip_info*** cinfos);
|
||||
|
||||
/* Multiple gpio support. */
|
||||
typedef struct _gpio_group* mraa_gpiod_group_t;
|
||||
|
||||
@@ -174,6 +174,11 @@ struct _gpio {
|
||||
++k) \
|
||||
if (dev->gpio_group[k].is_required)
|
||||
|
||||
#define for_each_gpio_chip(cinfo, cinfos, num_chips) \
|
||||
for (int idx = 0; \
|
||||
idx < num_chips && (cinfo = cinfos[idx]); \
|
||||
(idx++))
|
||||
|
||||
/**
|
||||
* A structure representing a I2C bus
|
||||
*/
|
||||
|
||||
116
src/gpio/gpio.c
116
src/gpio/gpio.c
@@ -163,6 +163,122 @@ init_internal_cleanup:
|
||||
return dev;
|
||||
}
|
||||
|
||||
mraa_gpio_context
|
||||
mraa_gpio_init_by_name(char* name)
|
||||
{
|
||||
mraa_board_t* board = plat;
|
||||
mraa_gpio_context dev;
|
||||
mraa_gpiod_group_t gpio_group;
|
||||
mraa_gpiod_line_info* linfo = NULL;
|
||||
mraa_gpiod_chip_info* cinfo;
|
||||
mraa_gpiod_chip_info** cinfos;
|
||||
int i, line_found, line_offset;
|
||||
|
||||
if (name == NULL) {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: Gpio name not valid");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!board->chardev_capable) {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: gpio_init_by_name not available for this platform!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = (mraa_gpio_context) calloc(1, sizeof(struct _gpio));
|
||||
if (dev == NULL) {
|
||||
syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->pin_to_gpio_table = malloc(sizeof(int));
|
||||
if (dev->pin_to_gpio_table == NULL) {
|
||||
syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member");
|
||||
mraa_gpio_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->num_chips = mraa_get_chip_infos(&cinfos);
|
||||
if (dev->num_chips <= 0) {
|
||||
mraa_gpio_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We are dealing with a single GPIO */
|
||||
dev->num_pins = 1;
|
||||
|
||||
gpio_group = calloc(dev->num_chips, sizeof(struct _gpio_group));
|
||||
if (gpio_group == NULL) {
|
||||
syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member");
|
||||
mraa_gpio_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->gpio_group = gpio_group;
|
||||
for (i = 0; i < dev->num_chips; ++i) {
|
||||
gpio_group[i].gpio_chip = i;
|
||||
gpio_group[i].gpio_lines = NULL;
|
||||
}
|
||||
|
||||
/* Iterate over all gpiochips in the platform to find the requested line */
|
||||
for_each_gpio_chip(cinfo, cinfos, dev->num_chips)
|
||||
{
|
||||
for (i = 0; i < cinfo->chip_info.lines; i++) {
|
||||
linfo = mraa_get_line_info_by_chip_name(cinfo->chip_info.name, i);
|
||||
if (!strncmp(linfo->name, name, 32)) {
|
||||
/* idx is coming from `for_each_gpio_chip` definition */
|
||||
syslog(LOG_DEBUG, "[GPIOD_INTERFACE]: Chip: %d Line: %d", idx, i);
|
||||
if (!gpio_group[idx].is_required) {
|
||||
gpio_group[idx].dev_fd = cinfo->chip_fd;
|
||||
gpio_group[idx].is_required = 1;
|
||||
gpio_group[idx].gpiod_handle = -1;
|
||||
}
|
||||
|
||||
/* Map pin to _gpio_group structure. */
|
||||
dev->pin_to_gpio_table[0] = idx;
|
||||
gpio_group[idx].gpio_lines = realloc(gpio_group[idx].gpio_lines, sizeof(unsigned int));
|
||||
gpio_group[idx].gpio_lines[0] = i;
|
||||
gpio_group[idx].num_gpio_lines++;
|
||||
|
||||
line_found = 1;
|
||||
line_offset = i;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!line_found) {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: Gpio not found!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize rw_values for read / write multiple functions */
|
||||
for (i = 0; i < dev->num_chips; ++i) {
|
||||
gpio_group[i].rw_values = calloc(gpio_group[i].num_gpio_lines, sizeof(unsigned char));
|
||||
if (gpio_group[i].rw_values == NULL) {
|
||||
syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member");
|
||||
mraa_gpio_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gpio_group[i].event_handles = NULL;
|
||||
}
|
||||
|
||||
/* Save the provided array from the user to our internal structure. */
|
||||
dev->provided_pins = malloc(dev->num_pins * sizeof(int));
|
||||
if (dev->provided_pins == NULL) {
|
||||
syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member");
|
||||
mraa_gpio_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(dev->provided_pins, &line_offset, dev->num_pins * sizeof(int));
|
||||
|
||||
dev->events = NULL;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
mraa_gpio_context
|
||||
mraa_gpio_init(int pin)
|
||||
{
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "gpio/gpio_chardev.h"
|
||||
#include "linux/gpio.h"
|
||||
#include "mraa_internal.h"
|
||||
#include "gpio/gpio_chardev.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
@@ -52,7 +52,8 @@ _mraa_free_gpio_groups(mraa_gpio_context dev)
|
||||
{
|
||||
mraa_gpiod_group_t gpio_iter;
|
||||
|
||||
for_each_gpio_group(gpio_iter, dev) {
|
||||
for_each_gpio_group(gpio_iter, dev)
|
||||
{
|
||||
if (gpio_iter->gpio_lines) {
|
||||
free(gpio_iter->gpio_lines);
|
||||
}
|
||||
@@ -105,7 +106,8 @@ _mraa_close_gpio_event_handles(mraa_gpio_context dev)
|
||||
{
|
||||
mraa_gpiod_group_t gpio_iter;
|
||||
|
||||
for_each_gpio_group(gpio_iter, dev) {
|
||||
for_each_gpio_group(gpio_iter, dev)
|
||||
{
|
||||
if (gpio_iter->event_handles != NULL) {
|
||||
for (int j = 0; j < gpio_iter->num_gpio_lines; ++j) {
|
||||
close(gpio_iter->event_handles[j]);
|
||||
@@ -124,7 +126,8 @@ _mraa_close_gpio_desc(mraa_gpio_context dev)
|
||||
{
|
||||
mraa_gpiod_group_t gpio_iter;
|
||||
|
||||
for_each_gpio_group(gpio_iter, dev) {
|
||||
for_each_gpio_group(gpio_iter, dev)
|
||||
{
|
||||
if (gpio_iter->gpiod_handle != -1) {
|
||||
close(gpio_iter->gpiod_handle);
|
||||
gpio_iter->gpiod_handle = -1;
|
||||
@@ -376,56 +379,85 @@ mraa_get_line_values(int line_handle, unsigned int num_lines, unsigned char outp
|
||||
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info *linfo)
|
||||
mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info* linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_KERNEL);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_dir_out(mraa_gpiod_line_info *linfo)
|
||||
mraa_is_gpio_line_dir_out(mraa_gpiod_line_info* linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_IS_OUT);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_active_low(mraa_gpiod_line_info *linfo)
|
||||
mraa_is_gpio_line_active_low(mraa_gpiod_line_info* linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_ACTIVE_LOW);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo)
|
||||
mraa_is_gpio_line_open_drain(mraa_gpiod_line_info* linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_OPEN_DRAIN);
|
||||
}
|
||||
|
||||
mraa_boolean_t
|
||||
mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo)
|
||||
mraa_is_gpio_line_open_source(mraa_gpiod_line_info* linfo)
|
||||
{
|
||||
return (linfo->flags & GPIOLINE_FLAG_OPEN_SOURCE);
|
||||
}
|
||||
|
||||
static int
|
||||
dir_filter(const struct dirent* dir)
|
||||
{
|
||||
return !strncmp(dir->d_name, CHIP_DEV_PREFIX, strlen(CHIP_DEV_PREFIX));
|
||||
}
|
||||
|
||||
int
|
||||
mraa_get_number_of_gpio_chips()
|
||||
{
|
||||
int num_chips = 0;
|
||||
DIR* dev_dir;
|
||||
struct dirent* dir;
|
||||
const unsigned int len = strlen(CHIP_DEV_PREFIX);
|
||||
int num_chips;
|
||||
struct dirent** dirs;
|
||||
|
||||
dev_dir = opendir(DEV_DIR);
|
||||
if (dev_dir) {
|
||||
while ((dir = readdir(dev_dir)) != NULL) {
|
||||
if (!strncmp(dir->d_name, CHIP_DEV_PREFIX, len)) {
|
||||
num_chips++;
|
||||
}
|
||||
}
|
||||
closedir(dev_dir);
|
||||
} else {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: opendir() error");
|
||||
num_chips = scandir("/dev", &dirs, dir_filter, alphasort);
|
||||
if (num_chips < 0) {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: scandir() error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Assume opendir() error. */
|
||||
return num_chips;
|
||||
}
|
||||
|
||||
int
|
||||
mraa_get_chip_infos(mraa_gpiod_chip_info*** cinfos)
|
||||
{
|
||||
int num_chips, i;
|
||||
struct dirent** dirs;
|
||||
mraa_gpiod_chip_info** cinfo;
|
||||
|
||||
num_chips = scandir("/dev", &dirs, dir_filter, alphasort);
|
||||
if (num_chips < 0) {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: scandir() error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cinfo = (mraa_gpiod_chip_info**) calloc(num_chips, sizeof(mraa_gpiod_chip_info*));
|
||||
if (!cinfo) {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: Failed to allocate memory for chip info");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get chip info for all gpiochips present in the platform */
|
||||
for (i = 0; i < num_chips; i++) {
|
||||
cinfo[i] = mraa_get_chip_info_by_name(dirs[i]->d_name);
|
||||
if (!cinfo[i]) {
|
||||
syslog(LOG_ERR, "[GPIOD_INTERFACE]: invalid chip %s", dirs[i]->d_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*cinfos = cinfo;
|
||||
|
||||
return num_chips;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user