diff --git a/Makefile b/Makefile index 4cdcb4e..658b749 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ TOOLS_CFLAGS := -Wall -std=c99 -D _DEFAULT_SOURCE # all: funkey_gpio_management -funkey_gpio_management: funkey_gpio_management.o gpio-utils.o uinput.o gpio_mapping.o read_conf_file.o keydefs.o driver_pcal6416a.o smbus.o +funkey_gpio_management: funkey_gpio_management.o gpio-utils.o uinput.o gpio_mapping.o read_conf_file.o keydefs.o driver_pcal6416a.o driver_axp209.o smbus.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ diff --git a/driver_axp209.c b/driver_axp209.c new file mode 100644 index 0000000..a4b61ae --- /dev/null +++ b/driver_axp209.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "read_conf_file.h" +#include +#include +#include +#include "smbus.h" +#include "driver_axp209.h" + +/**************************************************************** + * Defines + ****************************************************************/ +#define DEBUG_AXP209_PRINTF (1) + +#if (DEBUG_AXP209_PRINTF) + #define DEBUG_PRINTF(...) printf(__VA_ARGS__); +#else + #define DEBUG_PRINTF(...) +#endif + +/**************************************************************** + * Static variables + ****************************************************************/ +static int fd_axp209; +static char i2c0_sysfs_filename[] = "/dev/i2c-0"; + +/**************************************************************** + * Static functions + ****************************************************************/ + +/**************************************************************** + * Public functions + ****************************************************************/ +bool axp209_init(void) { + if ((fd_axp209 = open(i2c0_sysfs_filename,O_RDWR)) < 0) { + printf("In axp209_init - Failed to open the I2C bus %s", i2c0_sysfs_filename); + // ERROR HANDLING; you can check errno to see what went wrong + return false; + } + + if (ioctl(fd_axp209, I2C_SLAVE, AXP209_I2C_ADDR) < 0) { + printf("In axp209_init - Failed to acquire bus access and/or talk to slave.\n"); + // ERROR HANDLING; you can check errno to see what went wrong + return false; + } + + return true; +} + +bool axp209_deinit(void) { + // Close I2C open interface + close(fd_axp209); + return true; +} + +int axp209_read_interrupt_bank_3(void){ + int val = i2c_smbus_read_byte_data ( fd_axp209 , AXP209_INTERRUPT_BANK_3_STATUS ); + if(val < 0){ + return val; + } + DEBUG_PRINTF("READ AXP209_INTERRUPT_BANK_3_STATUS: 0x%02X\n",val); + return 0xFF & val; +} \ No newline at end of file diff --git a/driver_axp209.h b/driver_axp209.h new file mode 100644 index 0000000..ae5cabf --- /dev/null +++ b/driver_axp209.h @@ -0,0 +1,31 @@ +#ifndef _DRIVER_AXP209_H_ +#define _DRIVER_AXP209_H_ + + + /**************************************************************** + * Includes + ****************************************************************/ +#include + + /**************************************************************** + * Defines + ****************************************************************/ +// Chip physical address +#define AXP209_I2C_ADDR 0x34 + +// Chip registers adresses +#define AXP209_INTERRUPT_BANK_3_STATUS 0x4A + +// Masks +#define AXP209_INTERRUPT_PEK_SHORT_PRESS 0x02 +#define AXP209_INTERRUPT_PEK_LONG_PRESS 0x01 + +/**************************************************************** + * Public functions + ****************************************************************/ +bool axp209_init(void); +bool axp209_deinit(void); +int axp209_read_interrupt_bank_3(void); + + +#endif //_DRIVER_AXP209_H_ diff --git a/driver_axp209.o b/driver_axp209.o new file mode 100644 index 0000000..46e9c45 Binary files /dev/null and b/driver_axp209.o differ diff --git a/driver_pcal6416a.c b/driver_pcal6416a.c index 83a5836..2e234bf 100644 --- a/driver_pcal6416a.c +++ b/driver_pcal6416a.c @@ -29,8 +29,8 @@ /**************************************************************** * Static variables ****************************************************************/ -int fd_i2c_expander; -char i2c0_sysfs_filename[] = "/dev/i2c-0"; +static int fd_i2c_expander; +static char i2c0_sysfs_filename[] = "/dev/i2c-0"; /**************************************************************** * Static functions @@ -67,15 +67,23 @@ bool pcal6416a_deinit(void) { return true; } -uint16_t pcal6416a_read_mask_interrupts(void){ - uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INT_STATUS ); +int pcal6416a_read_mask_interrupts(void){ + int val_int = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INT_STATUS ); + if(val_int < 0){ + return val_int; + } + uint16_t val = val_int & 0xFFFF; DEBUG_PRINTF("READ PCAL6416A_INT_STATUS : 0x%04X\n",val); - return val; + return (int) val; } -uint16_t pcal6416a_read_mask_active_GPIOs(void){ - uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INPUT ); +int pcal6416a_read_mask_active_GPIOs(void){ + int val_int = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INPUT ); + if(val_int < 0){ + return val_int; + } + uint16_t val = val_int & 0xFFFF; val = 0xFFFF-val; DEBUG_PRINTF("READ PCAL6416A_INPUT (active GPIOs) : 0x%04X\n",val); - return val; + return (int) val; } \ No newline at end of file diff --git a/driver_pcal6416a.h b/driver_pcal6416a.h index 872efde..b3bd2e6 100644 --- a/driver_pcal6416a.h +++ b/driver_pcal6416a.h @@ -14,16 +14,16 @@ #define PCAL6416A_I2C_ADDR 0x20 // Chip registers adresses -#define PCAL6416A_INPUT 0x00 /* Input port [RO] */ +#define PCAL6416A_INPUT 0x00 /* Input port [RO] */ #define PCAL6416A_DAT_OUT 0x02 /* GPIO DATA OUT [R/W] */ #define PCAL6416A_POLARITY 0x04 /* Polarity Inversion port [R/W] */ #define PCAL6416A_CONFIG 0x06 /* Configuration port [R/W] */ -#define PCAL6416A_DRIVE0 0x40 /* Output drive strength Port0 [R/W] */ -#define PCAL6416A_DRIVE1 0x42 /* Output drive strength Port1 [R/W] */ +#define PCAL6416A_DRIVE0 0x40 /* Output drive strength Port0 [R/W] */ +#define PCAL6416A_DRIVE1 0x42 /* Output drive strength Port1 [R/W] */ #define PCAL6416A_INPUT_LATCH 0x44 /* Port0 Input latch [R/W] */ #define PCAL6416A_EN_PULLUPDOWN 0x46 /* Port0 Pull-up/Pull-down enbl [R/W] */ #define PCAL6416A_SEL_PULLUPDOWN 0x48 /* Port0 Pull-up/Pull-down slct [R/W] */ -#define PCAL6416A_INT_MASK 0x4A /* Interrupt mask [R/W] */ +#define PCAL6416A_INT_MASK 0x4A /* Interrupt mask [R/W] */ #define PCAL6416A_INT_STATUS 0x4C /* Interrupt status [RO] */ #define PCAL6416A_OUTPUT_CONFIG 0x4F /* Output port config [R/W] */ @@ -32,8 +32,8 @@ ****************************************************************/ bool pcal6416a_init(void); bool pcal6416a_deinit(void); -uint16_t pcal6416a_read_mask_interrupts(void); -uint16_t pcal6416a_read_mask_active_GPIOs(void); +int pcal6416a_read_mask_interrupts(void); +int pcal6416a_read_mask_active_GPIOs(void); #endif //_DRIVER_PCAL6416A_H_ diff --git a/driver_pcal6416a.o b/driver_pcal6416a.o index 3be6a6b..b86987a 100644 Binary files a/driver_pcal6416a.o and b/driver_pcal6416a.o differ diff --git a/funkey_gpio_management b/funkey_gpio_management index 1c7da8b..971738d 100755 Binary files a/funkey_gpio_management and b/funkey_gpio_management differ diff --git a/gpio-utils.c b/gpio-utils.c index 88a1559..bb9b0e1 100644 --- a/gpio-utils.c +++ b/gpio-utils.c @@ -1,33 +1,6 @@ -/* Copyright (c) 2011, RidgeRun +/* Copyright (c) 2019 FunKey * All rights reserved. * -From https://www.ridgerun.com/developer/wiki/index.php/Gpio-int-test.c - - * - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the RidgeRun. - * 4. Neither the name of the RidgeRun nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''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 RIDGERUN 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 "gpio-utils.h" diff --git a/gpio_mapping.c b/gpio_mapping.c index d63fe18..400d14e 100644 --- a/gpio_mapping.c +++ b/gpio_mapping.c @@ -12,6 +12,7 @@ #include #include "gpio_mapping.h" #include "driver_pcal6416a.h" +#include "driver_axp209.h" /**************************************************************** * Defines @@ -21,7 +22,7 @@ return(EXIT_FAILURE); \ } while(0) -#define DEBUG_GPIO_PRINTF (0) +#define DEBUG_GPIO_PRINTF (1) #define ERROR_GPIO_PRINTF (1) #if (DEBUG_GPIO_PRINTF) @@ -40,6 +41,9 @@ // If not declared, there will be no timeout and no periodical sanity check of GPIO expander values #define TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP 2 +// This is for debug purposes on cards or eval boards that do not have the AXP209 +//#define ENABLE_AXP209_INTERRUPTS + /**************************************************************** * Static variables @@ -48,9 +52,12 @@ static int nb_mapped_gpios; static int * gpio_pins; STRUCT_MAPPED_GPIO * chained_list_mapping; static int max_fd = 0; -static int gpio_fd_interrupt_i2c; +static int gpio_fd_interrupt_expander_gpio; +static int gpio_fd_interrupt_axp209; static fd_set fds; static bool * mask_gpio_value; +static bool interrupt_i2c_expander_found = false; +static bool interrupt_axp209_found = false; /**************************************************************** @@ -178,37 +185,37 @@ static void find_and_call_mapping_function(int idx_gpio_interrupted, } /***** Init GPIO Interrupt i2c expander fd *****/ -static int init_gpio_interrupt(void) +static int init_gpio_interrupt(int pin_nb, int *fd_saved) { // Variables - int cur_pin_nb = GPIO_PIN_I2C_EXPANDER_INTERRUPT; - GPIO_PRINTF("Initializing Interrupt i2c expander GPIO pin fd: %d\n", cur_pin_nb); + GPIO_PRINTF("Initializing Interrupt on GPIO pin: %d\n", pin_nb); // Init fds fd_set FD_ZERO(&fds); //Initializing I2C interrupt GPIO - gpio_export(cur_pin_nb); + gpio_export(pin_nb); //gpio_set_edge(cur_pin_nb, "both"); // Can be rising, falling or both - gpio_set_edge(cur_pin_nb, "falling"); // Can be rising, falling or both - gpio_fd_interrupt_i2c = gpio_fd_open(cur_pin_nb, O_RDONLY); + gpio_set_edge(pin_nb, "falling"); // Can be rising, falling or both + *fd_saved = gpio_fd_open(pin_nb, O_RDONLY); + GPIO_PRINTF("fd is: %d\n", *fd_saved); // add stdin and the sock fd to fds fd_set - safe_fd_set(gpio_fd_interrupt_i2c, &fds, &max_fd); + safe_fd_set(*fd_saved, &fds, &max_fd); return 0; } /***** DeInit GPIO Interrupt i2c expander fd *****/ -static int deinit_gpio_interrupt(void) +static int deinit_gpio_interrupt(int fd_saved) { - GPIO_PRINTF("DeInitializing Interrupt i2c expander GPIO pin fd\n"); + GPIO_PRINTF("DeInitializing Interrupt on GPIO pin fd: %d\n", fd_saved); // Remove stdin and sock fd from fds fd_set - safe_fd_clr(gpio_fd_interrupt_i2c, &fds, &max_fd); + safe_fd_clr(fd_saved, &fds, &max_fd); // Unexport GPIO - gpio_fd_close(gpio_fd_interrupt_i2c); + gpio_fd_close(fd_saved); return 0; } @@ -242,12 +249,22 @@ int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare, current = current->next_mapped_gpio; } while(current != NULL); - // Init GPIO interrupt from I2C expander - init_gpio_interrupt(); + // Init GPIO interrupt from I2C GPIO expander + GPIO_PRINTF(" Initiating interrupt for GPIO_PIN_I2C_EXPANDER_INTERRUPT\n"); + init_gpio_interrupt(GPIO_PIN_I2C_EXPANDER_INTERRUPT, &gpio_fd_interrupt_expander_gpio); // Init I2C expander pcal6416a_init(); +#ifdef ENABLE_AXP209_INTERRUPTS + // Init GPIO interrupt from AXP209 + GPIO_PRINTF(" Initiating interrupt for GPIO_PIN_AXP209_INTERRUPT\n"); + init_gpio_interrupt(GPIO_PIN_AXP209_INTERRUPT, &gpio_fd_interrupt_axp209); + + // Init AXP209 + axp209_init(); +#endif //ENABLE_AXP209_INTERRUPTS + return 0; } @@ -255,10 +272,21 @@ int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare, int deinit_mapping_gpios(void) { // DeInit GPIO interrupt from I2C expander - deinit_gpio_interrupt(); + GPIO_PRINTF(" DeInitiating interrupt for GPIO_PIN_I2C_EXPANDER_INTERRUPT\n"); + deinit_gpio_interrupt(gpio_fd_interrupt_expander_gpio); // DeInit I2C expander pcal6416a_deinit(); + +#ifdef ENABLE_AXP209_INTERRUPTS + // DeInit GPIO interrupt from AXP209 + GPIO_PRINTF(" DeInitiating interrupt for GPIO_PIN_AXP209_INTERRUPT\n"); + deinit_gpio_interrupt(gpio_fd_interrupt_axp209); + + // DeInit AXP209 + axp209_deinit(); +#endif //ENABLE_AXP209_INTERRUPTS + return 0; } @@ -267,12 +295,11 @@ int deinit_mapping_gpios(void) int listen_gpios_interrupts(void) { // Variables - char buffer[2]; - int idx_gpio, value; + //char buffer[2]; + //int value; + int idx_gpio; bool previous_mask_gpio_value[nb_mapped_gpios]; bool mask_gpio_current_interrupts[nb_mapped_gpios]; - uint16_t val_i2c_mask_interrupted, val_i2c_mask_active; - bool interrupt_found = false; // Back up master fd_set dup = fds; @@ -282,29 +309,31 @@ int listen_gpios_interrupts(void) memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool)); memset(mask_gpio_current_interrupts, false, nb_mapped_gpios*sizeof(bool)); - // Waiting for interrupt or timeout, Note the max_fd+1 + // If interrupt not already found, waiting for interrupt or timeout, Note the max_fd+1 + if(!interrupt_i2c_expander_found && !interrupt_axp209_found){ #ifdef TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP - struct timeval timeout = {TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP, 0}; - int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, &timeout); + struct timeval timeout = {TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP, 0}; + int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, &timeout); #else - int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, NULL); + int nb_interrupts = select(max_fd+1, NULL, NULL, &dup, NULL); #endif //TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP - if(!nb_interrupts){ - // Timeout case - GPIO_PRINTF(" Timeout, forcing sanity check\n"); - // Timeout forcing a "Found interrupt" event for sanity check - interrupt_found = true; - } - else if ( nb_interrupts < 0) { - perror("select"); - return -1; + if(!nb_interrupts){ + // Timeout case + GPIO_PRINTF(" Timeout, forcing sanity check\n"); + // Timeout forcing a "Found interrupt" event for sanity check + interrupt_i2c_expander_found = true; + } + else if ( nb_interrupts < 0) { + perror("select"); + return -1; + } } - // Check if interrupt from I2C expander + // Check if interrupt from I2C expander or AXP209 // Check which cur_fd is available for read for (int cur_fd = 0; cur_fd <= max_fd; cur_fd++) { if (FD_ISSET(cur_fd, &dup)) { - // Revenir au debut du fichier (lectures successives). + /*// Rewind file lseek(cur_fd, 0, SEEK_SET); // Read current gpio value @@ -313,19 +342,54 @@ int listen_gpios_interrupts(void) break; } - // Effacer le retour-chariot. + // remove end of line char buffer[1] = '\0'; - value = 1-atoi(buffer); + value = 1-atoi(buffer);*/ // Found interrupt - interrupt_found = true; + if(cur_fd == gpio_fd_interrupt_expander_gpio){ + interrupt_i2c_expander_found = true; + } + else if(cur_fd == gpio_fd_interrupt_axp209){ + interrupt_axp209_found = true; + } } } - if(interrupt_found){ + +#ifdef ENABLE_AXP209_INTERRUPTS + if(interrupt_axp209_found){ + GPIO_PRINTF(" Found interrupt AXP209\n"); + int val_int_bank_3 = axp209_read_interrupt_bank_3(); + if(val_int_bank_3 < 0){ + GPIO_PRINTF(" Could not read AXP209 with I2C\n"); + return 0; + } + interrupt_axp209_found = false; + + if(val_int_bank_3 & AXP209_INTERRUPT_PEK_SHORT_PRESS){ + GPIO_PRINTF(" AXP209 short PEK key press detected\n"); + } + if(val_int_bank_3 & AXP209_INTERRUPT_PEK_LONG_PRESS){ + GPIO_PRINTF(" AXP209 long PEK key press detected\n"); + } + } +#endif //ENABLE_AXP209_INTERRUPTS + + if(interrupt_i2c_expander_found){ // Read I2C GPIO masks: - val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts(); - val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs(); + int val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts(); + if(val_i2c_mask_interrupted < 0){ + GPIO_PRINTF(" Could not read pcal6416a_read_mask_interrupts\n"); + return 0; + } + int val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs(); + if(val_i2c_mask_active < 0){ + GPIO_PRINTF(" Could not read pcal6416a_read_mask_active_GPIOs\n"); + return 0; + } + interrupt_i2c_expander_found = false; + // Find GPIO idx correspondance for (idx_gpio=0; idx_gpio