From 3357fcb24a66333ca98c2424c0e50a510b44d8aa Mon Sep 17 00:00:00 2001 From: Kees Jongenburger Date: Wed, 6 Feb 2013 15:46:21 +0100 Subject: [PATCH] GPIO:further development * Generalize GPIO handling. * Add libs to configure gpio's clocks and pads * Add Interrupt handling. * Introduce mmio.h and log.h Change-Id: I928e4c807d15031de2eede4b3ecff62df795f8ac --- distrib/sets/lists/minix/md.evbarm | 6 +- distrib/sets/lists/minix/mi | 4 + drivers/gpio/Makefile | 4 +- drivers/gpio/gpio.c | 104 ++++-- drivers/gpio/gpio.h | 30 -- drivers/gpio/gpio_omap.c | 236 ------------- etc/system.conf | 11 +- include/minix/Makefile | 6 +- include/minix/gpio.h | 34 ++ {drivers/gpio => include/minix}/log.h | 7 +- {drivers/gpio => include/minix}/mmio.h | 5 +- include/minix/padconf.h | 184 ++++++++++ lib/Makefile | 6 +- lib/libgpio/Makefile | 10 + lib/libgpio/clkconf.c | 78 +++++ lib/libgpio/clkconf.h | 7 + lib/libgpio/gpio_omap.c | 447 +++++++++++++++++++++++++ lib/libpadconf/Makefile | 10 + lib/libpadconf/padconf.c | 100 ++++++ 19 files changed, 982 insertions(+), 307 deletions(-) delete mode 100644 drivers/gpio/gpio.h delete mode 100644 drivers/gpio/gpio_omap.c create mode 100644 include/minix/gpio.h rename {drivers/gpio => include/minix}/log.h (97%) rename {drivers/gpio => include/minix}/mmio.h (90%) create mode 100644 include/minix/padconf.h create mode 100644 lib/libgpio/Makefile create mode 100644 lib/libgpio/clkconf.c create mode 100644 lib/libgpio/clkconf.h create mode 100644 lib/libgpio/gpio_omap.c create mode 100644 lib/libpadconf/Makefile create mode 100644 lib/libpadconf/padconf.c diff --git a/distrib/sets/lists/minix/md.evbarm b/distrib/sets/lists/minix/md.evbarm index cebc658ba..2a60469e8 100644 --- a/distrib/sets/lists/minix/md.evbarm +++ b/distrib/sets/lists/minix/md.evbarm @@ -90,5 +90,9 @@ ./usr/include/evbarm/vmparam.h minix-sys ./usr/include/evbarm/wchar_limits.h minix-sys ./usr/include/i386 minix-sys obsolete -./usr/sbin/gpio minix-sys +./usr/lib/libgpio.a minix-sys +./usr/lib/libgpio_pic.a minix-sys +./usr/lib/libpadconf.a minix-sys +./usr/lib/libpadconf_pic.a minix-sys ./usr/mdec minix-sys +./usr/sbin/gpio minix-sys diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 69bc16829..4f2d16321 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -577,6 +577,7 @@ ./usr/include/minix/endpoint.h minix-sys ./usr/include/minix/fslib.h minix-sys ./usr/include/minix/gcov.h minix-sys +./usr/include/minix/gpio.h minix-sys ./usr/include/minix/hash.h minix-sys ./usr/include/minix/hgfs.h minix-sys ./usr/include/minix/input.h minix-sys @@ -586,13 +587,16 @@ ./usr/include/minix/keymap.h minix-sys ./usr/include/minix/libminixfs.h minix-sys ./usr/include/minix/limits.h minix-sys +./usr/include/minix/log.h minix-sys ./usr/include/minix minix-sys ./usr/include/minix/minlib.h minix-sys +./usr/include/minix/mmio.h minix-sys ./usr/include/minix/mount.h minix-sys ./usr/include/minix/mthread.h minix-sys ./usr/include/minix/netdriver.h minix-sys ./usr/include/minix/netsock.h minix-sys ./usr/include/minix/optset.h minix-sys +./usr/include/minix/padconf.h minix-sys ./usr/include/minix/param.h minix-sys ./usr/include/minix/partition.h minix-sys ./usr/include/minix/paths.h minix-sys diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a7f87f5a2..7cb5a9cc8 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -1,9 +1,9 @@ # Makefile for the gpio driver. PROG= gpio -SRCS= gpio.c gpio_omap.c +SRCS= gpio.c DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS} -LDADD+= -lvtreefs -lsys +LDADD+= -lvtreefs -lsys -lgpio -lpadconf # # This is a system driver. diff --git a/drivers/gpio/gpio.c b/drivers/gpio/gpio.c index 724b2664c..4163e5832 100644 --- a/drivers/gpio/gpio.c +++ b/drivers/gpio/gpio.c @@ -6,10 +6,16 @@ #include #include #include +#include +#include +#include +#include +#include /* system headers */ #include #include +#include /* usr headers */ #include @@ -21,9 +27,6 @@ #include /* local headers */ -#include "log.h" -#include "mmio.h" -#include "gpio.h" /* used for logging */ static struct log log = { @@ -33,8 +36,9 @@ static struct log log = { }; #define GPIO_CB_READ 0 -#define GPIO_CB_ON 1 -#define GPIO_CB_OFF 2 +#define GPIO_CB_INTR_READ 1 +#define GPIO_CB_ON 2 +#define GPIO_CB_OFF 3 /* The vtreefs library provides callback data when calling * the read function of inode. gpio_cbdata is used here to @@ -51,10 +55,10 @@ struct gpio_cbdata }; /* list of inodes used in this driver */ +/* *INDENT-OFF* */ TAILQ_HEAD(gpio_cbdata_head, gpio_cbdata) gpio_cbdata_list = TAILQ_HEAD_INITIALIZER(gpio_cbdata_list); - -static struct gpio_driver drv; +/* *INDENT-ON* */ /* Sane file stats for a directory */ static struct inode_stat default_file_stat = { @@ -75,13 +79,13 @@ add_gpio_inode(char *name, int nr, int mode) struct gpio *gpio; /* claim and configure the gpio */ - if (drv.claim("gpiofs", nr, &gpio)) { + if (gpio_claim("gpiofs", nr, &gpio)) { log_warn(&log, "Failed to claim GPIO %d\n", nr); return EIO; } assert(gpio != NULL); - if (drv.pin_mode(gpio, mode)) { + if (gpio_pin_mode(gpio, mode)) { log_warn(&log, "Failed to switch GPIO %d to mode %d\n", nr, mode); return EIO; @@ -115,7 +119,7 @@ add_gpio_inode(char *name, int nr, int mode) cb->type = GPIO_CB_ON; cb->gpio = gpio; - snprintf(tmpname, 200, "%son", name); + snprintf(tmpname, 200, "%sOn", name); add_inode(get_root_inode(), tmpname, NO_INDEX, &default_file_stat, 0, (cbdata_t) cb); TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next); @@ -130,7 +134,22 @@ add_gpio_inode(char *name, int nr, int mode) cb->type = GPIO_CB_OFF; cb->gpio = gpio; - snprintf(tmpname, 200, "%soff", name); + snprintf(tmpname, 200, "%sOff", name); + add_inode(get_root_inode(), tmpname, NO_INDEX, + &default_file_stat, 0, (cbdata_t) cb); + TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next); + } else { + /* read interrupt */ + cb = malloc(sizeof(struct gpio_cbdata)); + if (cb == NULL) { + return ENOMEM; + } + memset(cb, 0, sizeof(*cb)); + + cb->type = GPIO_CB_INTR_READ; + cb->gpio = gpio; + + snprintf(tmpname, 200, "%sIntr", name); add_inode(get_root_inode(), tmpname, NO_INDEX, &default_file_stat, 0, (cbdata_t) cb); TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next); @@ -142,17 +161,30 @@ static void init_hook(void) { /* This hook will be called once, after VTreeFS has initialized. */ - if (omap_gpio_init(&drv)) { + if (gpio_init()) { log_warn(&log, "Failed to init gpio driver\n"); } + add_gpio_inode("USR0", 149, GPIO_MODE_OUTPUT); add_gpio_inode("USR1", 150, GPIO_MODE_OUTPUT); add_gpio_inode("Button", 4, GPIO_MODE_INPUT); -#if 0 - add_gpio_inode("input1", 139, GPIO_MODE_INPUT); - add_gpio_inode("input2", 144, GPIO_MODE_INPUT); -#endif + /* configure the padconf */ + padconf_init(); + + /* configure GPIO_144 to be exported */ + padconf_set(CONTROL_PADCONF_UART2_CTS, 0xff, + PADCONF_MUXMODE(4) | PADCONF_PULL_MODE_PD_EN | + PADCONF_INPUT_ENABLE(1)); + padconf_set(CONTROL_PADCONF_MMC2_DAT6, 0xff00, + (PADCONF_MUXMODE(4) | PADCONF_PULL_MODE_PD_EN | + PADCONF_INPUT_ENABLE(1)) << 16); + + padconf_release(); + /* Added for demo purposes */ + add_gpio_inode("BigRedButton", 144, GPIO_MODE_INPUT); + add_gpio_inode("BigRedButtonLed", 139, GPIO_MODE_OUTPUT); + } static int @@ -167,28 +199,30 @@ static int struct gpio_cbdata *gpio_cbdata = (struct gpio_cbdata *) cbdata; assert(gpio_cbdata->gpio != NULL); - if (gpio_cbdata->type == GPIO_CB_ON) { - /* turn on */ - if (drv.set(gpio_cbdata->gpio, 1)) { + if (gpio_cbdata->type == GPIO_CB_ON + || gpio_cbdata->type == GPIO_CB_OFF) { + /* turn on or of */ + if (gpio_set(gpio_cbdata->gpio, + (gpio_cbdata->type == GPIO_CB_ON) ? 1 : 0)) { *len = 0; return EIO; } *len = 0; return OK; - } else if (gpio_cbdata->type == GPIO_CB_OFF) { - /* turn off */ - if (drv.set(gpio_cbdata->gpio, 0)) { + } + + if (gpio_cbdata->type == GPIO_CB_INTR_READ) { + /* reading interrupt */ + if (gpio_intr_read(gpio_cbdata->gpio, &value)) { + *len = 0; + return EIO; + } + } else { + /* reading */ + if (gpio_read(gpio_cbdata->gpio, &value)) { *len = 0; return EIO; } - *len = 0; - return OK; - } - - /* reading */ - if (drv.read(gpio_cbdata->gpio, &value)) { - *len = 0; - return EIO; } snprintf(data, 26, "%d\n", value); @@ -211,6 +245,13 @@ static int return OK; } +static int +message_hook(message * m) +{ + gpio_intr_message(m); + return OK; +} + int main(int argc, char **argv) { @@ -225,6 +266,7 @@ main(int argc, char **argv) memset(&hooks, 0, sizeof(hooks)); hooks.init_hook = init_hook; hooks.read_hook = read_hook; + hooks.message_hook = message_hook; root_stat.mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH; root_stat.uid = 0; @@ -233,7 +275,7 @@ main(int argc, char **argv) root_stat.dev = NO_DEV; /* limit the number of indexed entries */ - start_vtreefs(&hooks, 10, &root_stat, 0); + start_vtreefs(&hooks, 30, &root_stat, 0); return EXIT_SUCCESS; } diff --git a/drivers/gpio/gpio.h b/drivers/gpio/gpio.h deleted file mode 100644 index 5984ca8a3..000000000 --- a/drivers/gpio/gpio.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __INCLUDE_GPIO_H__ -#define __INCLUDE_GPIO_H__ - -struct gpio -{ - int nr; /* GPIO number */ - int mode; /* GPIO mode (input=0/output=1) */ - void *data; /* data pointer (not used in the omap driver) */ -}; - -#define GPIO_MODE_INPUT 0 -#define GPIO_MODE_OUTPUT 1 - -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 value of the GPIO */ - int (*read) (struct gpio * gpio, int *value); -}; - -int omap_gpio_init(struct gpio_driver *gpio_driver); -#endif /* __INCLUDE_GPIO_H__ */ diff --git a/drivers/gpio/gpio_omap.c b/drivers/gpio/gpio_omap.c deleted file mode 100644 index e2063a746..000000000 --- a/drivers/gpio/gpio_omap.c +++ /dev/null @@ -1,236 +0,0 @@ -/* kernel headers */ -#include -#include - -/* system headers */ -#include -#include - -/* usr headers */ -#include -#include -#include -#include -#include -#include - -/* local headers */ -#include "log.h" -#include "mmio.h" -#include "gpio.h" - -/* used for logging */ -static struct log log = { - .name = "gpio_omap", - .log_level = LEVEL_INFO, - .log_func = default_log -}; - -struct omap_gpio_bank -{ - const char *name; - uint32_t register_address; - uint32_t base_address; - uint32_t disabled; -}; - -static struct omap_gpio_bank omap_gpio_banks[] = { - {"GPIO1", 0x48310000, 0, 0}, - {"GPIO2", 0x49050000, 0, 0}, - {"GPIO3", 0x49052000, 0, 0}, - {"GPIO4", 0x49054000, 0, 0}, - {"GPIO5", 0x49056000, 0, 0}, - {"GPIO6", 0x49058000, 0, 0}, - {NULL, 0, 0} -}; - -#define GPIO_REVISION 0x00 -#define GPIO_REVISION_MAJOR(X) ((X & 0xF0) >> 4) -#define GPIO_REVISION_MINOR(X) (X & 0XF) - -#define GPIO_DATAOUT 0x3c -#define GPIO_DATAIN 0x38 -#define GPIO_OE 0x34 /* Output Data Enable */ -#define GPIO_CLEARDATAOUT 0x90 -#define GPIO_SETDATAOUT 0x94 - -#define LED_USR0 (1 << 21) -#define LED_USR1 (1 << 22) - -struct omap_gpio_bank * -omap_gpio_bank_get(int gpio_nr) -{ - struct omap_gpio_bank *bank; - assert(gpio_nr >= 0 && gpio_nr <= 32 * 6); - bank = &omap_gpio_banks[gpio_nr / 32]; - return bank; -} - -int -omap_gpio_claim(char *owner, int nr, struct gpio **gpio) -{ - log_trace(&log, "%s s claiming %d\n", owner, nr); - - if (nr < 0 && nr >= 32 * 6) { - log_warn(&log, "%s is claiming unknown GPIO number %d\n", owner, - nr); - return EINVAL; - } - - if ( omap_gpio_bank_get(nr)->disabled == 1) { - log_warn(&log, "%s is claiming GPIO %d from disabled bank\n", owner, - nr); - return EINVAL; - } - - struct gpio *tmp = malloc(sizeof(struct gpio)); - memset(tmp, 0, sizeof(*tmp)); - - tmp->nr = nr; - *gpio = tmp; - return OK; -} - -int -omap_gpio_pin_mode(struct gpio *gpio, int mode) -{ - struct omap_gpio_bank *bank; - assert(gpio != NULL); - gpio->mode = mode; - - bank = omap_gpio_bank_get(gpio->nr); - log_debug(&log, - "pin mode bank %s, base address 0x%x -> register address (0x%x,0x%x,0x%x)\n", - bank->name, bank->base_address, bank->register_address, GPIO_OE, - bank->register_address + GPIO_OE); - - if (mode == GPIO_MODE_OUTPUT) { - set32(bank->base_address + GPIO_OE, BIT(gpio->nr % 32), 0); - } else { - set32(bank->base_address + GPIO_OE, BIT(gpio->nr % 32), - 0xffffffff); - } - return 0; -} - -int -omap_gpio_set(struct gpio *gpio, int value) -{ - struct omap_gpio_bank *bank; - assert(gpio != NULL); - assert(gpio->nr >= 0 && gpio->nr <= 32 * 6); - - bank = omap_gpio_bank_get(gpio->nr); - if (value == 1) { - write32(bank->base_address + GPIO_SETDATAOUT, - BIT(gpio->nr % 32)); - } else { - write32(bank->base_address + GPIO_CLEARDATAOUT, - BIT(gpio->nr % 32)); - } - return OK; -} - -int -omap_gpio_read(struct gpio *gpio, int *value) -{ - struct omap_gpio_bank *bank; - assert(gpio != NULL); - assert(gpio->nr >= 0 && gpio->nr <= 32 * 6); - - bank = omap_gpio_bank_get(gpio->nr); - log_trace(&log, "mode=%d OU/IN 0x%08x 0x%08x\n", gpio->mode, - read32(bank->base_address + GPIO_DATAIN), - read32(bank->base_address + GPIO_DATAOUT)); - - if (gpio->mode == GPIO_MODE_INPUT) { - *value = - (read32(bank->base_address + - GPIO_DATAIN) >> (gpio->nr % 32)) & 0x1; - } else { - *value = - (read32(bank->base_address + - GPIO_DATAOUT) >> (gpio->nr % 32)) & 0x1; - } - - return OK; -} - -int -omap_gpio_init(struct gpio_driver *drv) -{ - u32_t revision; - int i; - struct minix_mem_range mr; - struct omap_gpio_bank *bank; - - bank = &omap_gpio_banks[0]; - for (i = 0; omap_gpio_banks[i].name != NULL; i++) { - bank = &omap_gpio_banks[i]; - mr.mr_base = bank->register_address; - mr.mr_limit = bank->register_address + 0x400; - - 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 */ - bank->base_address = - (uint32_t) vm_map_phys(SELF, - (void *) bank->register_address, 0x400); - - if (bank->base_address == (uint32_t) MAP_FAILED) { - log_warn(&log, "Unable to map GPIO memory\n"); - return EPERM; /* fixme */ - } - - revision = 0; - revision = read32(bank->base_address + GPIO_REVISION); - /* test if we can access it */ - if (GPIO_REVISION_MAJOR(revision) != 2 - || GPIO_REVISION_MINOR(revision) != 5) { - log_warn(&log, - "Failed to read the revision of GPIO bank %s.. disabling\n", - bank->name); - bank->disabled = 1; - } - bank->disabled = 0; - log_trace(&log, "bank %s mapped on 0x%x\n", bank->name, - bank->base_address); - } - -/* the following code need to move to a power management/clock service */ -#define CM_BASE 0x48004000 -#define CM_FCLKEN_WKUP 0xC00 -#define CM_ICLKEN_WKUP 0xC10 - - u32_t base; - mr.mr_base = CM_BASE; - mr.mr_limit = CM_BASE + 0x1000; - - if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { - log_warn(&log, "Unable to request permission to map memory\n"); - return EPERM; - } - - base = (uint32_t) vm_map_phys(SELF, (void *) CM_BASE, 0x1000); - - if (base == (uint32_t) MAP_FAILED) { - log_warn(&log, "Unable to map GPIO memory\n"); - return EPERM; - } - - /* enable the interface and functional clock on GPIO bank 1 */ - set32(base + CM_FCLKEN_WKUP, BIT(3), 0xffffffff); - set32(base + CM_ICLKEN_WKUP, BIT(3), 0xffffffff); -/* end power management/clock service stuff */ - - - drv->claim = omap_gpio_claim; - drv->pin_mode = omap_gpio_pin_mode; - drv->set = omap_gpio_set; - drv->read = omap_gpio_read; - return 0; -} diff --git a/etc/system.conf b/etc/system.conf index 154e940ac..9f8fe394e 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -552,14 +552,23 @@ service mmc IRQCTL # 19 ; irq 83; # IRQ 83 allowed - ; }; service gpio { system PRIVCTL # 4 + IRQCTL # 19 ; + irq + 29 # GPIO module 1 + 30 # GPIO module 2 + 31 # GPIO module 3 + 32 # GPIO module 4 + 33 # GPIO module 5 + 34 # GPIO module 6 + ; + }; service vbox diff --git a/include/minix/Makefile b/include/minix/Makefile index 4aaea7319..b72b98143 100644 --- a/include/minix/Makefile +++ b/include/minix/Makefile @@ -10,10 +10,10 @@ INCS+= acpi.h audio_fw.h bitmap.h \ config.h const.h cpufeature.h crtso.h \ debug.h devio.h devman.h dmap.h \ driver.h drivers.h drvlib.h ds.h \ - endpoint.h fslib.h gcov.h hash.h \ + endpoint.h fslib.h gpio.h gcov.h hash.h \ hgfs.h ioctl.h input.h ipc.h ipcconst.h \ - keymap.h limits.h mount.h mthread.h minlib.h \ - netdriver.h optset.h partition.h portio.h \ + keymap.h limits.h log.h mmio.h mount.h mthread.h minlib.h \ + netdriver.h optset.h padconf.h partition.h portio.h \ priv.h procfs.h profile.h queryparam.h \ rs.h safecopies.h sched.h sef.h sffs.h \ sound.h spin.h sys_config.h sysinfo.h \ diff --git a/include/minix/gpio.h b/include/minix/gpio.h new file mode 100644 index 000000000..d07e9f306 --- /dev/null +++ b/include/minix/gpio.h @@ -0,0 +1,34 @@ +#ifndef __INCLUDE_GPIO_H__ +#define __INCLUDE_GPIO_H__ + +struct gpio +{ + int nr; /* GPIO number */ + int mode; /* GPIO mode (input=0/output=1) */ +}; + +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 + +int gpio_init(); + +/* request access to a gpio */ +int gpio_claim(char *owner, int nr, struct gpio **gpio); + +/* Configure the GPIO for a certain purpose */ +int gpio_pin_mode(struct gpio *gpio, int mode); + +/* Set the value for a GPIO */ +int gpio_set(struct gpio *gpio, int value); + +/* Read the current value of the GPIO */ +int gpio_read(struct gpio *gpio, int *value); + +/* Read and clear the value interrupt value of the GPIO */ +int gpio_intr_read(struct gpio *gpio, int *value); + +/* Interrupt hook */ +int gpio_intr_message(message * m); + +int gpio_release(); +#endif /* __INCLUDE_GPIO_H__ */ diff --git a/drivers/gpio/log.h b/include/minix/log.h similarity index 97% rename from drivers/gpio/log.h rename to include/minix/log.h index b3d0c1768..a68f36b7c 100644 --- a/drivers/gpio/log.h +++ b/include/minix/log.h @@ -4,6 +4,8 @@ * Simple logging functions */ +#include + /* * LEVEL_NONE do not log anything. * LEVEL_WARN Information that needs to be known. @@ -41,7 +43,10 @@ static const char *level_string[5] = { * requested log level is debug or trace the method , file and line number will * be printed to the steam. */ -struct log { const char *name; int log_level; +struct log +{ + const char *name; + int log_level; /* the logging function itself */ void (*log_func) (struct log * driver, diff --git a/drivers/gpio/mmio.h b/include/minix/mmio.h similarity index 90% rename from drivers/gpio/mmio.h rename to include/minix/mmio.h index f40262a96..8c23a3520 100644 --- a/drivers/gpio/mmio.h +++ b/include/minix/mmio.h @@ -1,3 +1,6 @@ +#ifndef __MMIO_H__ +#define __MMIO_H__ + #define REG(x)(*((volatile uint32_t *)(x))) #define BIT(x)(0x1 << x) @@ -12,7 +15,6 @@ write32(uint32_t address, uint32_t value) static inline uint32_t read32(uint32_t address) { - return REG(address); } @@ -28,3 +30,4 @@ set32(uint32_t address, uint32_t mask, uint32_t value) val |= (value & mask); write32(address, val); } +#endif /* __MMIO_H__ */ diff --git a/include/minix/padconf.h b/include/minix/padconf.h new file mode 100644 index 000000000..8d8f7cc63 --- /dev/null +++ b/include/minix/padconf.h @@ -0,0 +1,184 @@ +#ifndef __PADCONF_H__ +#define __PADCONF_H__ + +#define PADCONF_REGISTERS_BASE 0x48002030 + +#define PADCONF_MUXMODE(X) (X & 0x7) /* mode 1 til 7 [2:0] */ +#define PADCONF_PULL_MODE(X) ((X & 0x3) << 3) /* 2 bits[4:3] */ +#define PADCONF_PULL_MODE_PD_DIS PADCONF_PULL_MODE(0) /* pull down disabled */ +#define PADCONF_PULL_MODE_PD_EN PADCONF_PULL_MODE(1) /* pull down enabled */ +#define PADCONF_PULL_MODE_PU_DIS PADCONF_PULL_MODE(2) /* pull up enabled */ +#define PADCONF_PULL_MODE_PU_EN PADCONF_PULL_MODE(3) /* pull up enabled */ +#define PADCONF_INPUT_ENABLE(X) ((X & 0x1) << 8) /* 1 bits[8] */ +#define PADCONF_OFF_MODE(X) ((X & 0xFE) << 9) /* 5 bits[13:9] */ + +/* padconf pin definitions */ +#define CONTROL_PADCONF_SDRC_D0 (0x00000000) +#define CONTROL_PADCONF_SDRC_D2 (0x00000004) +#define CONTROL_PADCONF_SDRC_D4 (0x00000008) +#define CONTROL_PADCONF_SDRC_D6 (0x0000000C) +#define CONTROL_PADCONF_SDRC_D8 (0x00000010) +#define CONTROL_PADCONF_SDRC_D10 (0x00000014) +#define CONTROL_PADCONF_SDRC_D12 (0x00000018) +#define CONTROL_PADCONF_SDRC_D14 (0x0000001C) +#define CONTROL_PADCONF_SDRC_D16 (0x00000020) +#define CONTROL_PADCONF_SDRC_D18 (0x00000024) +#define CONTROL_PADCONF_SDRC_D20 (0x00000028) +#define CONTROL_PADCONF_SDRC_D22 (0x0000002C) +#define CONTROL_PADCONF_SDRC_D24 (0x00000030) +#define CONTROL_PADCONF_SDRC_D26 (0x00000034) +#define CONTROL_PADCONF_SDRC_D28 (0x00000038) +#define CONTROL_PADCONF_SDRC_D30 (0x0000003C) +#define CONTROL_PADCONF_SDRC_CLK (0x00000040) +#define CONTROL_PADCONF_SDRC_DQS1 (0x00000044) +#define CONTROL_PADCONF_SDRC_DQS3 (0x00000048) +#define CONTROL_PADCONF_GPMC_A2 (0x0000004C) +#define CONTROL_PADCONF_GPMC_A4 (0x00000050) +#define CONTROL_PADCONF_GPMC_A6 (0x00000054) +#define CONTROL_PADCONF_GPMC_A8 (0x00000058) +#define CONTROL_PADCONF_GPMC_A10 (0x0000005C) +#define CONTROL_PADCONF_GPMC_D1 (0x00000060) +#define CONTROL_PADCONF_GPMC_D3 (0x00000064) +#define CONTROL_PADCONF_GPMC_D5 (0x00000068) +#define CONTROL_PADCONF_GPMC_D7 (0x0000006C) +#define CONTROL_PADCONF_GPMC_D9 (0x00000070) +#define CONTROL_PADCONF_GPMC_D11 (0x00000074) +#define CONTROL_PADCONF_GPMC_D13 (0x00000078) +#define CONTROL_PADCONF_GPMC_D15 (0x0000007C) +#define CONTROL_PADCONF_GPMC_NCS1 (0x00000080) +#define CONTROL_PADCONF_GPMC_NCS3 (0x00000084) +#define CONTROL_PADCONF_GPMC_NCS5 (0x00000088) +#define CONTROL_PADCONF_GPMC_NCS7 (0x0000008C) +#define CONTROL_PADCONF_GPMC_NADV_ALE (0x00000090) +#define CONTROL_PADCONF_GPMC_NWE (0x00000094) +#define CONTROL_PADCONF_GPMC_NBE1 (0x00000098) +#define CONTROL_PADCONF_GPMC_WAIT0 (0x0000009C) +#define CONTROL_PADCONF_GPMC_WAIT2 (0x000000A0) +#define CONTROL_PADCONF_DSS_PCLK (0x000000A4) +#define CONTROL_PADCONF_DSS_VSYNC (0x000000A8) +#define CONTROL_PADCONF_DSS_DATA0 (0x000000AC) +#define CONTROL_PADCONF_DSS_DATA2 (0x000000B0) +#define CONTROL_PADCONF_DSS_DATA4 (0x000000B4) +#define CONTROL_PADCONF_DSS_DATA6 (0x000000B8) +#define CONTROL_PADCONF_DSS_DATA8 (0x000000BC) +#define CONTROL_PADCONF_DSS_DATA10 (0x000000C0) +#define CONTROL_PADCONF_DSS_DATA12 (0x000000C4) +#define CONTROL_PADCONF_DSS_DATA14 (0x000000C8) +#define CONTROL_PADCONF_DSS_DATA16 (0x000000CC) +#define CONTROL_PADCONF_DSS_DATA18 (0x000000D0) +#define CONTROL_PADCONF_DSS_DATA20 (0x000000D4) +#define CONTROL_PADCONF_DSS_DATA22 (0x000000D8) +#define CONTROL_PADCONF_CAM_HS (0x000000DC) +#define CONTROL_PADCONF_CAM_XCLKA (0x000000E0) +#define CONTROL_PADCONF_CAM_FLD (0x000000E4) +#define CONTROL_PADCONF_CAM_D1 (0x000000E8) +#define CONTROL_PADCONF_CAM_D3 (0x000000EC) +#define CONTROL_PADCONF_CAM_D5 (0x000000F0) +#define CONTROL_PADCONF_CAM_D7 (0x000000F4) +#define CONTROL_PADCONF_CAM_D9 (0x000000F8) +#define CONTROL_PADCONF_CAM_D11 (0x000000FC) +#define CONTROL_PADCONF_CAM_WEN (0x00000100) +#define CONTROL_PADCONF_CSI2_DX0 (0x00000104) +#define CONTROL_PADCONF_CSI2_DX1 (0x00000108) +#define CONTROL_PADCONF_MCBSP2_FSX (0x0000010C) +#define CONTROL_PADCONF_MCBSP2_DR (0x00000110) +#define CONTROL_PADCONF_MMC1_CLK (0x00000114) +#define CONTROL_PADCONF_MMC1_DAT0 (0x00000118) +#define CONTROL_PADCONF_MMC1_DAT2 (0x0000011C) +#define CONTROL_PADCONF_MMC2_CLK (0x00000128) +#define CONTROL_PADCONF_MMC2_DAT0 (0x0000012C) +#define CONTROL_PADCONF_MMC2_DAT2 (0x00000130) +#define CONTROL_PADCONF_MMC2_DAT4 (0x00000134) +#define CONTROL_PADCONF_MMC2_DAT6 (0x00000138) +#define CONTROL_PADCONF_MCBSP3_DX (0x0000013C) +#define CONTROL_PADCONF_MCBSP3_CLKX (0x00000140) +#define CONTROL_PADCONF_UART2_CTS (0x00000144) +#define CONTROL_PADCONF_UART2_TX (0x00000148) +#define CONTROL_PADCONF_UART1_TX (0x0000014C) +#define CONTROL_PADCONF_UART1_CTS (0x00000150) +#define CONTROL_PADCONF_MCBSP4_CLKX (0x00000154) +#define CONTROL_PADCONF_MCBSP4_DX (0x00000158) +#define CONTROL_PADCONF_MCBSP1_CLKR (0x0000015C) +#define CONTROL_PADCONF_MCBSP1_DX (0x00000160) +#define CONTROL_PADCONF_MCBSP_CLKS (0x00000164) +#define CONTROL_PADCONF_MCBSP1_CLKX (0x00000168) +#define CONTROL_PADCONF_UART3_RTS_SD (0x0000016C) +#define CONTROL_PADCONF_UART3_TX_IRTX (0x00000170) +#define CONTROL_PADCONF_HSUSB0_STP (0x00000174) +#define CONTROL_PADCONF_HSUSB0_NXT (0x00000178) +#define CONTROL_PADCONF_HSUSB0_DATA1 (0x0000017C) +#define CONTROL_PADCONF_HSUSB0_DATA3 (0x00000180) +#define CONTROL_PADCONF_HSUSB0_DATA5 (0x00000184) +#define CONTROL_PADCONF_HSUSB0_DATA7 (0x00000188) +#define CONTROL_PADCONF_I2C1_SDA (0x0000018C) +#define CONTROL_PADCONF_I2C2_SDA (0x00000190) +#define CONTROL_PADCONF_I2C3_SDA (0x00000194) +#define CONTROL_PADCONF_MCSPI1_CLK (0x00000198) +#define CONTROL_PADCONF_MCSPI1_SOMI (0x0000019C) +#define CONTROL_PADCONF_MCSPI1_CS1 (0x000001A0) +#define CONTROL_PADCONF_MCSPI1_CS3 (0x000001A4) +#define CONTROL_PADCONF_MCSPI2_SIMO (0x000001A8) +#define CONTROL_PADCONF_MCSPI2_CS0 (0x000001AC) +#define CONTROL_PADCONF_SYS_NIRQ (0x000001B0) +#define CONTROL_PADCONF_SAD2D_MCAD0 (0x000001B4) +#define CONTROL_PADCONF_SAD2D_MCAD2 (0x000001B8) +#define CONTROL_PADCONF_SAD2D_MCAD4 (0x000001BC) +#define CONTROL_PADCONF_SAD2D_MCAD6 (0x000001C0) +#define CONTROL_PADCONF_SAD2D_MCAD8 (0x000001C4) +#define CONTROL_PADCONF_SAD2D_MCAD10 (0x000001C8) +#define CONTROL_PADCONF_SAD2D_MCAD12 (0x000001CC) +#define CONTROL_PADCONF_SAD2D_MCAD14 (0x000001D0) +#define CONTROL_PADCONF_SAD2D_MCAD16 (0x000001D4) +#define CONTROL_PADCONF_SAD2D_MCAD18 (0x000001D8) +#define CONTROL_PADCONF_SAD2D_MCAD20 (0x000001DC) +#define CONTROL_PADCONF_SAD2D_MCAD22 (0x000001E0) +#define CONTROL_PADCONF_SAD2D_MCAD24 (0x000001E4) +#define CONTROL_PADCONF_SAD2D_MCAD26 (0x000001E8) +#define CONTROL_PADCONF_SAD2D_MCAD28 (0x000001EC) +#define CONTROL_PADCONF_SAD2D_MCAD30 (0x000001F0) +#define CONTROL_PADCONF_SAD2D_MCAD32 (0x000001F4) +#define CONTROL_PADCONF_SAD2D_MCAD34 (0x000001F8) +#define CONTROL_PADCONF_SAD2D_MCAD36 (0x000001FC) +#define CONTROL_PADCONF_SAD2D_NRESPWRON (0x00000200) +#define CONTROL_PADCONF_SAD2D_ARMNIRQ (0x00000204) +#define CONTROL_PADCONF_SAD2D_SPINT (0x00000208) +#define CONTROL_PADCONF_SAD2D_DMAREQ0 (0x0000020C) +#define CONTROL_PADCONF_SAD2D_DMAREQ2 (0x00000210) +#define CONTROL_PADCONF_SAD2D_NTRST (0x00000214) +#define CONTROL_PADCONF_SAD2D_TDO (0x00000218) +#define CONTROL_PADCONF_SAD2D_TCK (0x0000021C) +#define CONTROL_PADCONF_SAD2D_MSTDBY (0x00000220) +#define CONTROL_PADCONF_SAD2D_IDLEACK (0x00000224) +#define CONTROL_PADCONF_SAD2D_SWRITE (0x00000228) +#define CONTROL_PADCONF_SAD2D_SREAD (0x0000022C) +#define CONTROL_PADCONF_SAD2D_SBUSFLAG (0x00000230) +#define CONTROL_PADCONF_SDRC_CKE1 (0x00000234) +#define CONTROL_PADCONF_SDRC_BA0 (0x00000570) +#define CONTROL_PADCONF_SDRC_A0 (0x00000574) +#define CONTROL_PADCONF_SDRC_A2 (0x00000578) +#define CONTROL_PADCONF_SDRC_A4 (0x0000057C) +#define CONTROL_PADCONF_SDRC_A6 (0x00000580) +#define CONTROL_PADCONF_SDRC_A8 (0x00000584) +#define CONTROL_PADCONF_SDRC_A10 (0x00000588) +#define CONTROL_PADCONF_SDRC_A12 (0x0000058C) +#define CONTROL_PADCONF_SDRC_A14 (0x00000590) +#define CONTROL_PADCONF_SDRC_NCS1 (0x00000594) +#define CONTROL_PADCONF_SDRC_NRAS (0x00000598) +#define CONTROL_PADCONF_SDRC_NWE (0x0000059C) +#define CONTROL_PADCONF_SDRC_DM1 (0x000005A0) +#define CONTROL_PADCONF_SDRC_DM3 (0x000005A4) +#define CONTROL_PADCONF_ETK_CLK (0x000005A8) +#define CONTROL_PADCONF_ETK_D0 (0x000005AC) +#define CONTROL_PADCONF_ETK_D2 (0x000005B0) +#define CONTROL_PADCONF_ETK_D4 (0x000005B4) +#define CONTROL_PADCONF_ETK_D6 (0x000005B8) +#define CONTROL_PADCONF_ETK_D8 (0x000005BC) +#define CONTROL_PADCONF_ETK_D10 (0x000005C0) +#define CONTROL_PADCONF_ETK_D12 (0x000005C4) +#define CONTROL_PADCONF_ETK_D14 (0x000005C8) + +int padconf_init(); +int padconf_set(u32_t padconf, u32_t mask, u32_t value); +int padconf_release(); + +#endif /* __PADCONF_H__ */ diff --git a/lib/Makefile b/lib/Makefile index da4349856..92ab84941 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -45,10 +45,14 @@ SUBDIR+= libcompat_minix libblockdriver libchardriver \ libutil libbz2 libprop \ libnetsock libpuffs libsffs -.if (${MACHINE} == "i386") +.if (${MACHINE_ARCH} == "i386") SUBDIR += libvassert libhgfs libvboxfs libvirtio .endif +.if (${MACHINE_ARCH} == "earm") +SUBDIR += libgpio libpadconf +.endif + .if (${MKRUMP} != "no") SUBDIR+= librumpclient .endif diff --git a/lib/libgpio/Makefile b/lib/libgpio/Makefile new file mode 100644 index 000000000..4e27eb3bb --- /dev/null +++ b/lib/libgpio/Makefile @@ -0,0 +1,10 @@ +# Makefile for libmthread + +CPPFLAGS+=-O -D_MINIX -D_POSIX_SOURCE -Wall -Werror -D_SYSTEM + +LIB= gpio + +SRCS= \ + gpio_omap.c clkconf.c + +.include diff --git a/lib/libgpio/clkconf.c b/lib/libgpio/clkconf.c new file mode 100644 index 000000000..7fb73cdfe --- /dev/null +++ b/lib/libgpio/clkconf.c @@ -0,0 +1,78 @@ +/* kernel headers */ +#include +#include +#include +#include + +/* system headers */ +#include +#include + +/* usr headers */ +#include +#include +#include +#include +#include +#include + +/* local headers */ +#include "clkconf.h" + +/* used for logging */ +static struct log log = { + .name = "omap_clkconf", + .log_level = LEVEL_INFO, + .log_func = default_log +}; + +#define CM_BASE 0x48004000 +static u32_t base = 0; +static u32_t use_count = 0; + +int +clkconf_init() +{ + use_count++; + + if (base != 0) { + /* when used in a library we can't guaranty we only call this + * method once */ + log_trace(&log, "Called %d times\n", use_count); + return OK; + } + struct minix_mem_range mr; + mr.mr_base = CM_BASE; + mr.mr_limit = CM_BASE + 0x1000; + + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + log_warn(&log, "Unable to request permission to map memory\n"); + return EPERM; + } + + base = (uint32_t) vm_map_phys(SELF, (void *) CM_BASE, 0x1000); + + if (base == (uint32_t) MAP_FAILED) { + log_warn(&log, "Unable to map GPIO memory\n"); + return EPERM; + } + return OK; +} + +int +clkconf_set(u32_t clk, u32_t mask, u32_t value) +{ + set32(base + clk, mask, value); + return OK; +} + +int +clkconf_release() +{ + assert(use_count > 0); + use_count--; + if (use_count == 0) { + vm_unmap_phys(SELF, (void *) base, 0x1000); + } + return OK; +} diff --git a/lib/libgpio/clkconf.h b/lib/libgpio/clkconf.h new file mode 100644 index 000000000..deba8a2c2 --- /dev/null +++ b/lib/libgpio/clkconf.h @@ -0,0 +1,7 @@ +/* Clock configuration */ +#define CM_FCLKEN_WKUP 0xC00 +#define CM_ICLKEN_WKUP 0xC10 + +int clkconf_init(); +int clkconf_set(u32_t clk, u32_t mask, u32_t value); +int clkconf_release(); diff --git a/lib/libgpio/gpio_omap.c b/lib/libgpio/gpio_omap.c new file mode 100644 index 000000000..dcfc10a29 --- /dev/null +++ b/lib/libgpio/gpio_omap.c @@ -0,0 +1,447 @@ +/* kernel headers */ +#include +#include +#include +#include +#include + +/* system headers */ +#include +#include + +/* usr headers */ +#include +#include +#include +#include +#include +#include + +#include "clkconf.h" + +/* local headers */ + +/* used for logging */ +static struct log log = { + .name = "gpio_omap", + .log_level = LEVEL_INFO, + .log_func = default_log +}; + +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; + +struct omap_gpio_bank +{ + const char *name; + uint32_t register_address; + uint32_t irq_nr; /* irq number */ + uint32_t base_address; + int32_t disabled; + int irq_id; /* orignhal hook id??? */ + int irq_hook_id; /* hook id */ + uint32_t inter_values; /* values when the interrupt was called */ +}; + +#define GPIO1_BASE (0x48310000) +#define GPIO2_BASE (0x49050000) +#define GPIO3_BASE (0x49052000) +#define GPIO4_BASE (0x49054000) +#define GPIO5_BASE (0x49056000) +#define GPIO6_BASE (0x49058000) +#define GPIO1_IRQ 29 /* GPIO module 1 */ +#define GPIO2_IRQ 30 /* GPIO module 2 */ +#define GPIO3_IRQ 31 /* GPIO module 3 */ +#define GPIO4_IRQ 32 /* GPIO module 4 */ +#define GPIO5_IRQ 33 /* GPIO module 5 */ +#define GPIO6_IRQ 34 /* GPIO module 6 */ +#define GPIO1_IRQ_HOOK_ID 0 +#define GPIO2_IRQ_HOOK_ID 1 +#define GPIO3_IRQ_HOOK_ID 2 +#define GPIO4_IRQ_HOOK_ID 3 +#define GPIO5_IRQ_HOOK_ID 4 +#define GPIO6_IRQ_HOOK_ID 5 + +#define GPIO_IRQSTATUS1 (0x18) +#define GPIO_IRQENABLE1 (0x01C) +#define GPIO_DATAOUT (0x3c) +#define GPIO_DATAIN (0x38) +#define GPIO_OE (0x34) /* Output Data Enable */ +#define GPIO_RISINGDETECT1 (0x048) +#define GPIO_FALLINGDETECT1 (0x04c) +#define GPIO_CLEARDATAOUT (0x90) +#define GPIO_SETDATAOUT (0x94) + +static struct omap_gpio_bank omap_gpio_banks[] = { + { + .name = "GPIO1", + .register_address = GPIO1_BASE, + .irq_nr = GPIO1_IRQ, + .base_address = 0, + .disabled = 0, + .irq_id = GPIO1_IRQ_HOOK_ID, + .irq_hook_id = GPIO1_IRQ_HOOK_ID, + }, + { + .name = "GPIO2", + .register_address = GPIO2_BASE, + .irq_nr = GPIO2_IRQ, + .base_address = 0, + .disabled = 0, + .irq_id = GPIO2_IRQ_HOOK_ID, + .irq_hook_id = GPIO2_IRQ_HOOK_ID, + }, + { + .name = "GPIO3", + .register_address = GPIO3_BASE, + .irq_nr = GPIO3_IRQ, + .base_address = 0, + .disabled = 0, + .irq_id = GPIO3_IRQ_HOOK_ID, + .irq_hook_id = GPIO3_IRQ_HOOK_ID, + }, + { + .name = "GPIO4", + .register_address = GPIO4_BASE, + .irq_nr = GPIO4_IRQ, + .base_address = 0, + .disabled = 0, + .irq_id = GPIO4_IRQ_HOOK_ID, + .irq_hook_id = GPIO4_IRQ_HOOK_ID, + }, + { + .name = "GPIO5", + .register_address = GPIO5_BASE, + .irq_nr = GPIO5_IRQ, + .base_address = 0, + .disabled = 0, + .irq_id = GPIO5_IRQ_HOOK_ID, + .irq_hook_id = GPIO5_IRQ_HOOK_ID, + }, + { + .name = "GPIO6", + .register_address = GPIO6_BASE, + .irq_nr = GPIO6_IRQ, + .base_address = 0, + .disabled = 0, + .irq_id = GPIO6_IRQ_HOOK_ID, + .irq_hook_id = GPIO6_IRQ_HOOK_ID, + }, + {NULL, 0, 0} +}; + +#define GPIO_REVISION 0x00 +#define GPIO_REVISION_MAJOR(X) ((X & 0xF0) >> 4) +#define GPIO_REVISION_MINOR(X) (X & 0XF) + +struct omap_gpio_bank * +omap_gpio_bank_get(int gpio_nr) +{ + struct omap_gpio_bank *bank; + assert(gpio_nr >= 0 && gpio_nr <= 32 * 6); + bank = &omap_gpio_banks[gpio_nr / 32]; + return bank; +} + +int +omap_gpio_claim(char *owner, int nr, struct gpio **gpio) +{ + log_trace(&log, "%s s claiming %d\n", owner, nr); + + if (nr < 0 && nr >= 32 * 6) { + log_warn(&log, "%s is claiming unknown GPIO number %d\n", + owner, nr); + return EINVAL; + } + + if (omap_gpio_bank_get(nr)->disabled == 1) { + log_warn(&log, "%s is claiming GPIO %d from disabled bank\n", + owner, nr); + return EINVAL; + } + + struct gpio *tmp = malloc(sizeof(struct gpio)); + memset(tmp, 0, sizeof(*tmp)); + + tmp->nr = nr; + *gpio = tmp; + return OK; +} + +int +omap_gpio_pin_mode(struct gpio *gpio, int mode) +{ + struct omap_gpio_bank *bank; + assert(gpio != NULL); + gpio->mode = mode; + + bank = omap_gpio_bank_get(gpio->nr); + log_debug(&log, + "pin mode bank %s, base address 0x%x -> register address (0x%x,0x%x,0x%x)\n", + bank->name, bank->base_address, bank->register_address, GPIO_OE, + bank->register_address + GPIO_OE); + + if (mode == GPIO_MODE_OUTPUT) { + set32(bank->base_address + GPIO_OE, BIT(gpio->nr % 32), 0); + } else { + set32(bank->base_address + GPIO_FALLINGDETECT1, + BIT(gpio->nr % 32), 0xffffffff); + set32(bank->base_address + GPIO_IRQENABLE1, BIT(gpio->nr % 32), + 0xffffffff); + set32(bank->base_address + GPIO_OE, BIT(gpio->nr % 32), + 0xffffffff); + } + return 0; +} + +int +omap_gpio_set(struct gpio *gpio, int value) +{ + struct omap_gpio_bank *bank; + assert(gpio != NULL); + assert(gpio->nr >= 0 && gpio->nr <= 32 * 6); + + bank = omap_gpio_bank_get(gpio->nr); + if (value == 1) { + write32(bank->base_address + GPIO_SETDATAOUT, + BIT(gpio->nr % 32)); + } else { + write32(bank->base_address + GPIO_CLEARDATAOUT, + BIT(gpio->nr % 32)); + } + return OK; +} + +int +omap_gpio_read(struct gpio *gpio, int *value) +{ + struct omap_gpio_bank *bank; + assert(gpio != NULL); + assert(gpio->nr >= 0 && gpio->nr <= 32 * 6); + + bank = omap_gpio_bank_get(gpio->nr); + log_trace(&log, "mode=%d OU/IN 0x%08x 0x%08x\n", gpio->mode, + read32(bank->base_address + GPIO_DATAIN), + read32(bank->base_address + GPIO_DATAOUT)); + + if (gpio->mode == GPIO_MODE_INPUT) { + *value = + (read32(bank->base_address + + GPIO_DATAIN) >> (gpio->nr % 32)) & 0x1; + } else { + *value = + (read32(bank->base_address + + GPIO_DATAOUT) >> (gpio->nr % 32)) & 0x1; + } + + return OK; +} + +int +omap_gpio_intr_read(struct gpio *gpio, int *value) +{ + struct omap_gpio_bank *bank; + assert(gpio != NULL); + assert(gpio->nr >= 0 && gpio->nr <= 32 * 6); + + bank = omap_gpio_bank_get(gpio->nr); + /* TODO: check if interrupt where enabled?? */ + + *value = (bank->inter_values >> (gpio->nr % 32)) & 0x1; + /* clear the data */ + bank->inter_values &= ~(1 << (gpio->nr % 32)); + + return OK; +} + +int +omap_message_hook(message * m) +{ + unsigned long irq_set, i; + struct omap_gpio_bank *bank; + + switch (_ENDPOINT_P(m->m_source)) { + case HARDWARE: + /* Hardware interrupt return a "set" if pending interrupts */ + irq_set = m->NOTIFY_ARG; + log_debug(&log, "HW message 0X%08x\n", m->NOTIFY_ARG); + bank = &omap_gpio_banks[0]; + for (i = 0; omap_gpio_banks[i].name != NULL; i++) { + bank = &omap_gpio_banks[i]; + + if (irq_set & (1 << (bank->irq_id))) { + log_trace(&log, "Interrupt for bank %s\n", + bank->name); + bank->inter_values |= + read32(bank->base_address + + GPIO_IRQSTATUS1); + /* clear the interrupts */ + write32(bank->base_address + GPIO_IRQSTATUS1, + 0xffffffff); + if (sys_irqenable(&bank->irq_hook_id) != OK) { + log_warn(&log, + "Failed to enable irq for bank %s\n", + bank->name); + } + } + } + return OK; + default: + log_warn(&log, "Unknown message\n"); + break; + } + return OK; +} + +int +omap_gpio_init(struct gpio_driver *drv) +{ + u32_t revision; + int i; + struct minix_mem_range mr; + struct omap_gpio_bank *bank; + + bank = &omap_gpio_banks[0]; + for (i = 0; omap_gpio_banks[i].name != NULL; i++) { + bank = &omap_gpio_banks[i]; + mr.mr_base = bank->register_address; + mr.mr_limit = bank->register_address + 0x400; + + 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 */ + bank->base_address = + (uint32_t) vm_map_phys(SELF, + (void *) bank->register_address, 0x400); + + if (bank->base_address == (uint32_t) MAP_FAILED) { + log_warn(&log, "Unable to map GPIO memory\n"); + return EPERM; /* fixme */ + } + + revision = 0; + revision = read32(bank->base_address + GPIO_REVISION); + /* test if we can access it */ + if (GPIO_REVISION_MAJOR(revision) != 2 + || GPIO_REVISION_MINOR(revision) != 5) { + log_warn(&log, + "Failed to read the revision of GPIO bank %s.. disabling\n", + bank->name); + bank->disabled = 1; + } + bank->disabled = 0; + + if (sys_irqsetpolicy(bank->irq_nr, 0, + &bank->irq_hook_id) != OK) { + log_warn(&log, + "GPIO: couldn't set IRQ policy for bank %s\n", + bank->name); + continue; + }; + if (bank->irq_id != bank->irq_hook_id) { + log_debug(&log, "requested id %d but got id %d\n", + bank->irq_id, bank->irq_hook_id); + } + if (sys_irqenable(&bank->irq_hook_id) != OK) { + log_warn(&log, + "GPIO: couldn't enable interrupt for %s\n", + bank->name); + }; + log_trace(&log, "bank %s mapped on 0x%x with irq hook id %d\n", + bank->name, bank->base_address, bank->irq_hook_id); + + }; + + clkconf_init(); + /* enable the interface and functional clock on GPIO bank 1 */ + clkconf_set(CM_FCLKEN_WKUP, BIT(3), 0xffffffff); + clkconf_set(CM_ICLKEN_WKUP, BIT(3), 0xffffffff); + clkconf_release(); + + + drv->claim = omap_gpio_claim; + drv->pin_mode = omap_gpio_pin_mode; + drv->set = omap_gpio_set; + drv->read = omap_gpio_read; + drv->intr_read = omap_gpio_intr_read; + drv->message_hook = omap_message_hook; + return 0; +} + +int +gpio_init() +{ + return omap_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() +{ + return OK; +} diff --git a/lib/libpadconf/Makefile b/lib/libpadconf/Makefile new file mode 100644 index 000000000..fd2c713d9 --- /dev/null +++ b/lib/libpadconf/Makefile @@ -0,0 +1,10 @@ +# Makefile for libpadconf + +CPPFLAGS+=-O -D_MINIX -D_POSIX_SOURCE -Wall -Werror -D_SYSTEM + +LIB= padconf + +SRCS= \ + padconf.c + +.include diff --git a/lib/libpadconf/padconf.c b/lib/libpadconf/padconf.c new file mode 100644 index 000000000..c1b4d80a7 --- /dev/null +++ b/lib/libpadconf/padconf.c @@ -0,0 +1,100 @@ +/* kernel headers */ +#include +#include +#include +#include +#include + +/* system headers */ +#include +#include + +/* usr headers */ +#include +#include +#include +#include +#include +#include + +/* local headers */ + +/* used for logging */ +static struct log log = { + .name = "omap_padconf", + .log_level = LEVEL_INFO, + .log_func = default_log +}; + +static u32_t base = 0; +static u32_t use_count = 0; + +int +padconf_init() +{ + struct minix_mem_range mr; + + use_count++; + + if (base != 0) { + /* when used in a library we can't guaranty we only call this + * method once */ + log_trace(&log, "Called %d times\n", use_count); + return OK; + } + mr.mr_base = PADCONF_REGISTERS_BASE; + mr.mr_limit = PADCONF_REGISTERS_BASE + 0x1000; + + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + log_warn(&log, "Unable to request permission to map memory\n"); + return EPERM; + } + + base = + (uint32_t) vm_map_phys(SELF, (void *) PADCONF_REGISTERS_BASE, + 0x1000); + + if (base == (uint32_t) MAP_FAILED) { + log_warn(&log, "Unable to map GPIO memory\n"); + return EPERM; + } + + mr.mr_base = PADCONF_REGISTERS_BASE; + mr.mr_limit = PADCONF_REGISTERS_BASE + 0x1000; + + if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { + log_warn(&log, "Unable to request permission to map memory\n"); + return EPERM; + } + + base = + (uint32_t) vm_map_phys(SELF, (void *) PADCONF_REGISTERS_BASE, + 0x1000); + + if (base == (uint32_t) MAP_FAILED) { + log_warn(&log, "Unable to map GPIO memory\n"); + return EPERM; + } + return OK; +} + +int +padconf_set(u32_t padconf, u32_t mask, u32_t value) +{ + assert(padconf <= CONTROL_PADCONF_ETK_D14); + set32(base + padconf, mask, value); + return OK; +} + +int +padconf_release() +{ + assert(use_count > 0); + use_count--; + + if (use_count == 0) { + vm_unmap_phys(SELF, (void *) base, 0x1000); + } + base = 0; + return OK; +} -- 2.44.0