diff --git a/minix/drivers/system/gpio/gpio.c b/minix/drivers/system/gpio/gpio.c index e6c2928fb..9c296af86 100644 --- a/minix/drivers/system/gpio/gpio.c +++ b/minix/drivers/system/gpio/gpio.c @@ -205,7 +205,16 @@ init_hook(void) CONTROL_CONF_PUDEN | CONTROL_CONF_MUXMODE(7))); add_gpio_inode("RIGHT", (32 * 1) + 17, GPIO_MODE_INPUT); + } else if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)) { + /* Export GPIO 26 as SLIDE_PREV */ + add_gpio_inode("SLIDE_PREV", 26, GPIO_MODE_INPUT); + /* Export GPIO 21 as SLIDE_NEXT */ + add_gpio_inode("SLIDE_NEXT", 21, GPIO_MODE_INPUT); + /* Put both of them in pull-up */ + sys_padconf(0x94, 0x3, 2); + sys_padconf(0x98, 0xffffffff, (1<<26)|(1<<21)); + sys_padconf(0x98, 0xffffffff, 0); } } diff --git a/minix/include/minix/gpio.h b/minix/include/minix/gpio.h index 14000304f..f46439bd3 100644 --- a/minix/include/minix/gpio.h +++ b/minix/include/minix/gpio.h @@ -9,6 +9,12 @@ struct gpio #define GPIO_MODE_INPUT 0 #define GPIO_MODE_OUTPUT 1 +#define GPIO_MODE_ALT0 2 +#define GPIO_MODE_ALT1 3 +#define GPIO_MODE_ALT2 4 +#define GPIO_MODE_ALT3 5 +#define GPIO_MODE_ALT4 6 +#define GPIO_MODE_ALT5 7 int gpio_init(void); diff --git a/minix/lib/libgpio/Makefile b/minix/lib/libgpio/Makefile index ee86fbf27..b0e861abb 100644 --- a/minix/lib/libgpio/Makefile +++ b/minix/lib/libgpio/Makefile @@ -4,8 +4,13 @@ CPPFLAGS+= -D_SYSTEM -D_MINIX_SYSTEM LIB= gpio -SRCS= \ - gpio_omap.c +.if ${BSP_NAME} == omap +SRCS= gpio_omap.c +.elif ${BSP_NAME} == rpi +SRCS= gpio_rpi.c +.else +.error Unknown bsp ${BSP_NAME} +.endif WARNS?= 5 diff --git a/minix/lib/libgpio/gpio_rpi.c b/minix/lib/libgpio/gpio_rpi.c new file mode 100644 index 000000000..137c1e9bf --- /dev/null +++ b/minix/lib/libgpio/gpio_rpi.c @@ -0,0 +1,224 @@ +/* kernel headers */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* system headers */ +#include +#include + +/* usr headers */ +#include +#include +#include +#include +#include +#include + +/* local headers */ +#include + +/* used for logging */ +static struct log log = { + .name = "gpio_rpi", + .log_level = LEVEL_INFO, + .log_func = default_log +}; + +static uint32_t rpi_gpio_base_address; + +struct gpio_driver +{ + /* request access to a gpio */ + int (*claim) (char *owner, int nr, struct gpio ** gpio); + + /* Configure the GPIO for a certain purpose */ + int (*pin_mode) (struct gpio * gpio, int mode); + + /* Set the value for a GPIO */ + int (*set) (struct gpio * gpio, int value); + + /* Read the current value of the GPIO */ + int (*read) (struct gpio * gpio, int *value); + + /* Read and clear the value interrupt value of the GPIO */ + int (*intr_read) (struct gpio * gpio, int *value); + + /* Interrupt hook */ + int (*message_hook) (message * m); +}; + +static struct gpio_driver drv; + +static int +rpi_gpio_claim(char *owner, int nr, struct gpio **gpio) +{ + log_trace(&log, "%s s claiming %d\n", owner, nr); + + if (nr < 0 && nr > 53) { + log_warn(&log, "%s is claiming unknown GPIO number %d\n", + owner, nr); + return EINVAL; + } + + struct gpio *tmp = malloc(sizeof(struct gpio)); + memset(tmp, 0, sizeof(*tmp)); + + tmp->nr = nr; + *gpio = tmp; + return OK; +} + +static int +rpi_gpio_pin_mode(struct gpio *gpio, int mode) +{ + assert(gpio != NULL); + gpio->mode = mode; + + log_debug(&log, "pin %d mode %d\n", gpio->nr, mode); + + int gpio_reg = gpio->nr / 10; + int gpio_offset = (gpio->nr % 10) * 3; + + set32(rpi_gpio_base_address + 4*gpio_reg, 0x7 << gpio_offset, mode << gpio_offset); + + return 0; +} + +static int +rpi_gpio_set(struct gpio *gpio, int value) +{ + assert(gpio != NULL); + assert(gpio->nr >= 0 && gpio->nr <= 53); + + int gpio_reg = gpio->nr / 32; + + if (value == 1) { + write32(rpi_gpio_base_address + 0x1c + 4*gpio_reg, + BIT(gpio->nr % 32)); + } else { + write32(rpi_gpio_base_address + 0x28 + 4*gpio_reg, + BIT(gpio->nr % 32)); + } + return OK; +} + +static int +rpi_gpio_read(struct gpio *gpio, int *value) +{ + assert(gpio != NULL); + assert(gpio->nr >= 0 && gpio->nr <= 53); + + int gpio_reg = gpio->nr / 32; + + *value = (read32(rpi_gpio_base_address + 0x34 + 4*gpio_reg) >> + (gpio->nr % 32)) & 0x1; + + return OK; +} + +static int +rpi_gpio_intr_read(struct gpio *gpio, int *value) +{ + /* No interrupts yet */ + return OK; +} + +static int +rpi_message_hook(message * m) +{ + /* No interrupts yet */ + return OK; +} + +static int +rpi_gpio_init(struct gpio_driver *gpdrv) +{ + struct minix_mem_range mr; + + mr.mr_base = PADCONF_RPI2_REGISTERS_BASE; + mr.mr_limit = mr.mr_base + PADCONF_RPI2_REGISTERS_SIZE; + + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + log_warn(&log, + "Unable to request permission to map memory\n"); + return EPERM; /* fixme */ + } + + /* Set the base address to use */ + rpi_gpio_base_address = + (uint32_t) vm_map_phys(SELF, + (void *) PADCONF_RPI2_REGISTERS_BASE, PADCONF_RPI2_REGISTERS_SIZE); + + if (rpi_gpio_base_address == (uint32_t) MAP_FAILED) { + log_warn(&log, "Unable to map GPIO memory\n"); + return EPERM; /* fixme */ + } + + gpdrv->claim = rpi_gpio_claim; + gpdrv->pin_mode = rpi_gpio_pin_mode; + gpdrv->set = rpi_gpio_set; + gpdrv->read = rpi_gpio_read; + gpdrv->intr_read = rpi_gpio_intr_read; + gpdrv->message_hook = rpi_message_hook; + return 0; +} + +int +gpio_init() +{ + return rpi_gpio_init(&drv); +} + +/* request access to a gpio */ +int +gpio_claim(char *owner, int nr, struct gpio **gpio) +{ + return drv.claim(owner, nr, gpio); +} + +/* Configure the GPIO for a certain purpose */ +int +gpio_pin_mode(struct gpio *gpio, int mode) +{ + return drv.pin_mode(gpio, mode); +} + +/* Set the value for a GPIO */ +int +gpio_set(struct gpio *gpio, int value) +{ + return drv.set(gpio, value); +} + +/* Read the current value of the GPIO */ +int +gpio_read(struct gpio *gpio, int *value) +{ + return drv.read(gpio, value); +} + +/* Read and clear the value interrupt value of the GPIO */ +int +gpio_intr_read(struct gpio *gpio, int *value) +{ + return drv.intr_read(gpio, value); +} + +/* Interrupt hook */ +int +gpio_intr_message(message * m) +{ + return drv.message_hook(m); +} + +int +gpio_release(void) +{ + return OK; +}