From b7699d374ab17e6054d0d83a9deb7be9e70dcdc8 Mon Sep 17 00:00:00 2001 From: Lucio Tarantino Date: Sat, 6 Jun 2020 18:47:11 +0200 Subject: [PATCH] linux: Ability to use multiple GPIO chips (#2935) Signed-off-by: Lucio Tarantino --- docs/Config_Changes.md | 5 ++++ src/linux/analog.c | 2 +- src/linux/gpio.c | 60 +++++++++++++++++++++++++++++------------- src/linux/internal.h | 6 +++++ 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/docs/Config_Changes.md b/docs/Config_Changes.md index 2dd92d0d..3226b80e 100644 --- a/docs/Config_Changes.md +++ b/docs/Config_Changes.md @@ -5,6 +5,11 @@ document when upgrading the Klipper software. All dates in this document are approximate. # Changes +2020xxxx: The the GPIO name on linux_mcu has changed. It is now in the +`gpiochip/gpio`, for gpiochip0 you can also use a short +`gpio`. +For example, what was previously referred to as `P20` now becomes +`gpio20` or `gpiochip0/gpio20`. 20200603: The default 16x4 LCD layout will no longer show the estimated time remaining in a print. (Only the elapsed time will be diff --git a/src/linux/analog.c b/src/linux/analog.c index aa8fb701..55420ce6 100644 --- a/src/linux/analog.c +++ b/src/linux/analog.c @@ -15,7 +15,7 @@ DECL_CONSTANT("ADC_MAX", 4095); // Assume 12bit adc -#define ANALOG_START (1<<8) +#define ANALOG_START (1<<12) DECL_ENUMERATION_RANGE("pin", "analog0", ANALOG_START, 8); diff --git a/src/linux/gpio.c b/src/linux/gpio.c index d8990581..a858b259 100644 --- a/src/linux/gpio.c +++ b/src/linux/gpio.c @@ -19,45 +19,65 @@ #include #include -#define CHIP_FILE_NAME "/dev/gpiochip0" +#define CHIP_FILE_NAME "/dev/gpiochip%u" #define GPIO_CONSUMER "klipper" -#define NUM_LINES 40 -DECL_ENUMERATION_RANGE("pin", "P0", 0, NUM_LINES); + +DECL_ENUMERATION_RANGE("pin", "gpio0", GPIO(0, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip0/gpio0", GPIO(0, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip1/gpio0", GPIO(1, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip2/gpio0", GPIO(2, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip3/gpio0", GPIO(3, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip4/gpio0", GPIO(4, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip5/gpio0", GPIO(5, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip6/gpio0", GPIO(6, 0), MAX_GPIO_LINES); +DECL_ENUMERATION_RANGE("pin", "gpiochip7/gpio0", GPIO(7, 0), MAX_GPIO_LINES); struct gpio_line { + int chipid; int offset; int fd; int state; }; -static struct gpio_line lines[NUM_LINES]; +static struct gpio_line lines[8*MAX_GPIO_LINES]; -static int gpio_chip_fd = -1; +static int gpio_chip_fd[8] = { -1 }; static int -get_chip_fd(void) { +get_chip_fd(uint8_t chipId) { + char chipFilename[64],errorMessage[256]; int i = 0; - if (gpio_chip_fd <= 0) { - gpio_chip_fd = open(CHIP_FILE_NAME,O_RDWR | O_CLOEXEC); - if (gpio_chip_fd < 0) { - report_errno("open " CHIP_FILE_NAME,-1); + if (gpio_chip_fd[chipId] <= 0) { + snprintf(chipFilename,sizeof(chipFilename), CHIP_FILE_NAME, chipId); + if(access(chipFilename, F_OK) < 0){ + snprintf(errorMessage,sizeof(errorMessage), + "%s not found!",chipFilename); + report_errno(errorMessage,-1); + shutdown("GPIO chip device not found"); + } + gpio_chip_fd[chipId] = open(chipFilename,O_RDWR | O_CLOEXEC); + if (gpio_chip_fd[chipId] < 0) { + snprintf(errorMessage,sizeof(errorMessage), + "Unable to open GPIO %s",chipFilename); + report_errno(errorMessage,-1); shutdown("Unable to open GPIO chip device"); } - for (i=0; ioffset = pin; + line->offset = GPIO2PIN(pin); + line->chipid = GPIO2PORT(pin); struct gpio_out g = { .line = line }; gpio_out_reset(g,val); return g; @@ -84,7 +104,7 @@ gpio_out_reset(struct gpio_out g, uint8_t val) req.lineoffsets[0] = g.line->offset; req.default_values[0] = !!val; strncpy(req.consumer_label,GPIO_CONSUMER,sizeof(req.consumer_label) - 1); - rv = ioctl(get_chip_fd(), GPIO_GET_LINEHANDLE_IOCTL, &req); + rv = ioctl(get_chip_fd(g.line->chipid), GPIO_GET_LINEHANDLE_IOCTL, &req); if (rv < 0) { report_errno("gpio_out_reset get line",rv); shutdown("Unable to open out GPIO chip line"); @@ -120,7 +140,8 @@ struct gpio_in gpio_in_setup(uint32_t pin, int8_t pull_up) { struct gpio_line* line = &lines[pin]; - line->offset = pin; + line->offset = GPIO2PIN(pin); + line->chipid = GPIO2PORT(pin); struct gpio_in g = { .line = line }; gpio_in_reset(g,pull_up); return g; @@ -144,7 +165,8 @@ gpio_in_reset(struct gpio_in g, int8_t pull_up) #endif req.lineoffsets[0] = g.line->offset; strncpy(req.consumer_label,GPIO_CONSUMER,sizeof(req.consumer_label) - 1); - rv = ioctl(get_chip_fd(), GPIO_GET_LINEHANDLE_IOCTL, &req); + rv = ioctl( + get_chip_fd(g.line->chipid),GPIO_GET_LINEHANDLE_IOCTL,&req); if (rv < 0) { report_errno("gpio_in_reset get line",rv); shutdown("Unable to open in GPIO chip line"); diff --git a/src/linux/internal.h b/src/linux/internal.h index 592c4588..ac4f3f13 100644 --- a/src/linux/internal.h +++ b/src/linux/internal.h @@ -5,6 +5,12 @@ #include // struct timespec #include "autoconf.h" // CONFIG_CLOCK_FREQ +#define MAX_GPIO_LINES 256 +#define GPIO(PORT, NUM) ((PORT) * MAX_GPIO_LINES + (NUM)) +#define GPIO2PORT(PIN) ((PIN) / MAX_GPIO_LINES) +#define GPIO2PIN(PIN) ((PIN) % MAX_GPIO_LINES) + + #define NSECS 1000000000 #define NSECS_PER_TICK (NSECS / CONFIG_CLOCK_FREQ)