Commit e314e30f authored by Jeroen Vreeken's avatar Jeroen Vreeken
Browse files

Add GPIO blocks

parent 89022ffc
......@@ -223,6 +223,47 @@
#define AM335X_ADC_FACTOR (1.8/4096.0)
#define AM335X_GPIO0_BASE 0x44e07000
#define AM335X_GPIO1_BASE 0x4804c000
#define AM335X_GPIO2_BASE 0x481ac000
#define AM335X_GPIO3_BASE 0x481ae000
#define AM335X_GPIO_SIZE 0x00001000
#define AM335X_GPIO_REG_REVISION 0x000
#define AM335X_GPIO_REVISION_FUNC_GET(x) (((x) & 0x0fff0000) >> 16)
#define AM335X_GPIO_REVISION_FUNC 0x060
#define AM335X_GPIO_REVISION_X_MAJOR_GET(x) (((x) & 0x00000700) >> 8)
#define AM335X_GPIO_REVISION_Y_MINOR_GET(x) (((x) & 0x0000003f) )
#define AM335X_GPIO_REG_SYSCONF 0x010
#define AM335X_GPIO_REG_EOI 0x020
#define AM335X_GPIO_REG_IRQSTATUS_RAW_0 0x024
#define AM335X_GPIO_REG_IRQSTATUS_RAW_1 0x028
#define AM335X_GPIO_REG_IRQSTATUS_0 0x02c
#define AM335X_GPIO_REG_IRQSTATUS_1 0x030
#define AM335X_GPIO_REG_IRQSTATUS_SET_0 0x034
#define AM335X_GPIO_REG_IRQSTATUS_SET_1 0x038
#define AM335X_GPIO_REG_IRQSTATUS_CLR_0 0x03c
#define AM335X_GPIO_REG_IRQSTATUS_CLR_1 0x040
#define AM335X_GPIO_REG_IRQWAKEN_0 0x044
#define AM335X_GPIO_REG_IRQWAKEN_1 0x048
#define AM335X_GPIO_REG_SYSSTATUS 0x114
#define AM335X_GPIO_REG_CTRL 0x130
#define AM335X_GPIO_REG_OE 0x134
#define AM335X_GPIO_REG_DATAIN 0x138
#define AM335X_GPIO_REG_DATAOUT 0x13c
#define AM335X_GPIO_REG_LEVELDETECT0 0x140
#define AM335X_GPIO_REG_LEVELDETECT1 0x144
#define AM335X_GPIO_REG_RISINGDETECT 0x148
#define AM335X_GPIO_REG_FALLINGDETECT 0x14c
#define AM335X_GPIO_REG_DEBOUNCENABLE 0x150
#define AM335X_GPIO_REG_DEBOUNCINGTIME 0x154
#define AM335X_GPIO_REG_CLEARDATAOUT 0x190
#define AM335X_GPIO_REG_SETDATAOUT 0x194
static inline uint32_t am335x_read32(void *base, size_t reg_offset)
{
volatile uint32_t *reg = (uint32_t *)((char *)base + reg_offset);
......
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2014
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "am335x.h"
#include <controller/controller_block.h>
#include <log/log.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <math.h>
struct controller_block_private {
bool in;
uint32_t bitmask;
void *base;
};
static void gpi_calculate(struct controller_block *gpi)
{
struct controller_block_private *priv = gpi->private;
bool in;
uint32_t reg;
void *base = priv->base;
reg = am335x_read32(base, AM335X_GPIO_REG_DATAIN);
in = reg & gpi->private->bitmask;
priv->in = in;
}
static struct controller_block_outterm_list outterms[] = {
{ "in", CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, in) },
{ NULL },
};
struct controller_block * block_am335x_gpi_create(char *name, va_list ap)
{
struct controller_block *gpi;
int fd;
void *base;
uint32_t reg;
uint32_t notpin;
int gpi_nr;
int pin_nr;
size_t offset;
gpi_nr = va_arg(ap, int);
if (gpi_nr < 0 || gpi_nr > 3) {
log_send(LOG_T_ERROR, "%s: gpio%d is not valid. (valid: 0-3)",
name, gpi_nr);
return NULL;
}
switch (gpi_nr) {
case 0:
offset = AM335X_GPIO0_BASE;
break;
case 1:
offset = AM335X_GPIO1_BASE;
break;
case 2:
offset = AM335X_GPIO2_BASE;
break;
case 3:
offset = AM335X_GPIO3_BASE;
break;
}
pin_nr = va_arg(ap, int);
if (pin_nr < 0 || pin_nr > 31) {
log_send(LOG_T_ERROR, "%s: pin%d is not valid. (valid: 0-31)",
name, pin_nr);
return NULL;
}
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0 ) {
log_send(LOG_T_ERROR, "%s: Error opening /dev/mem", name);
close(fd);
return NULL;
}
base = mmap(NULL, AM335X_GPIO_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, offset);
close(fd);
if (!base) {
log_send(LOG_T_ERROR, "Mapping GPIO failed");
return NULL;
}
log_send(LOG_T_DEBUG, "%s: GPIO%d (0x%"PRIx32") mapped @ %p", name,
gpi_nr, offset, base);
reg = am335x_read32(base, AM335X_GPIO_REG_REVISION);
log_send(LOG_T_DEBUG,
"%s: REVISION: 0x%" PRIx32 ": func: 0x%03x rev: %d.%d",
name, reg, AM335X_GPIO_REVISION_FUNC_GET(reg),
AM335X_GPIO_REVISION_X_MAJOR_GET(reg),
AM335X_GPIO_REVISION_Y_MINOR_GET(reg));
if (AM335X_GPIO_REVISION_FUNC_GET(reg) != AM335X_GPIO_REVISION_FUNC) {
log_send(LOG_T_ERROR, "Unexpected functional number");
goto err_rev;
}
if (!(gpi = controller_block_alloc("am355x_gpi", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_outterm_list_init(gpi, outterms))
goto err_outterm;
gpi->private->base = base;
gpi->private->bitmask = 1 << pin_nr;
notpin = ~gpi->private->bitmask;
am335x_write32(base, AM335X_GPIO_REG_LEVELDETECT0,
am335x_read32(base, AM335X_GPIO_REG_LEVELDETECT0) & notpin);
am335x_write32(base, AM335X_GPIO_REG_LEVELDETECT1,
am335x_read32(base, AM335X_GPIO_REG_LEVELDETECT1) & notpin);
am335x_write32(base, AM335X_GPIO_REG_RISINGDETECT,
am335x_read32(base, AM335X_GPIO_REG_RISINGDETECT) & notpin);
am335x_write32(base, AM335X_GPIO_REG_FALLINGDETECT,
am335x_read32(base, AM335X_GPIO_REG_FALLINGDETECT) & notpin);
/* configure as output */
am335x_write32(base, AM335X_GPIO_REG_OE,
am335x_read32(base, AM335X_GPIO_REG_OE) | gpi->private->bitmask);
gpi->calculate = gpi_calculate;
controller_block_add(gpi);
return gpi;
err_outterm:
controller_block_free(gpi);
err_alloc:
err_rev:
munmap(base, AM335X_GPIO_SIZE);
return NULL;
}
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2014
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "am335x.h"
#include <controller/controller_block.h>
#include <log/log.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
#include <math.h>
struct controller_block_private {
bool *out;
uint32_t bitmask;
void *base;
};
static void gpo_calculate(struct controller_block *gpo)
{
struct controller_block_private *priv = gpo->private;
bool out;
void *base = priv->base;
size_t regoff;
out = *priv->out;
regoff = out ?
AM335X_GPIO_REG_SETDATAOUT :
AM335X_GPIO_REG_CLEARDATAOUT;
am335x_write32(base, regoff, gpo->private->bitmask);
}
static struct controller_block_interm_list interms[] = {
{ "out", CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, out) },
{ NULL },
};
struct controller_block * block_am335x_gpo_create(char *name, va_list ap)
{
struct controller_block *gpo;
int fd;
void *base;
uint32_t reg;
uint32_t notpin;
int gpo_nr;
int pin_nr;
size_t offset;
gpo_nr = va_arg(ap, int);
if (gpo_nr < 0 || gpo_nr > 3) {
log_send(LOG_T_ERROR, "%s: gpio%d is not valid. (valid: 0-3)",
name, gpo_nr);
return NULL;
}
switch (gpo_nr) {
case 0:
offset = AM335X_GPIO0_BASE;
break;
case 1:
offset = AM335X_GPIO1_BASE;
break;
case 2:
offset = AM335X_GPIO2_BASE;
break;
case 3:
offset = AM335X_GPIO3_BASE;
break;
}
pin_nr = va_arg(ap, int);
if (pin_nr < 0 || pin_nr > 31) {
log_send(LOG_T_ERROR, "%s: pin%d is not valid. (valid: 0-31)",
name, pin_nr);
return NULL;
}
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0 ) {
log_send(LOG_T_ERROR, "%s: Error opening /dev/mem", name);
close(fd);
return NULL;
}
base = mmap(NULL, AM335X_GPIO_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, offset);
close(fd);
if (!base) {
log_send(LOG_T_ERROR, "Mapping GPIO failed");
return NULL;
}
log_send(LOG_T_DEBUG, "%s: GPIO%d (0x%"PRIx32") mapped @ %p", name,
gpo_nr, offset, base);
reg = am335x_read32(base, AM335X_GPIO_REG_REVISION);
log_send(LOG_T_DEBUG,
"%s: REVISION: 0x%" PRIx32 ": func: 0x%03x rev: %d.%d",
name, reg, AM335X_GPIO_REVISION_FUNC_GET(reg),
AM335X_GPIO_REVISION_X_MAJOR_GET(reg),
AM335X_GPIO_REVISION_Y_MINOR_GET(reg));
if (AM335X_GPIO_REVISION_FUNC_GET(reg) != AM335X_GPIO_REVISION_FUNC) {
log_send(LOG_T_ERROR, "Unexpected functional number");
goto err_rev;
}
if (!(gpo = controller_block_alloc("am355x_gpo", name, sizeof(struct controller_block_private))))
goto err_alloc;
if (controller_block_interm_list_init(gpo, interms))
goto err_interm;
gpo->private->base = base;
gpo->private->bitmask = 1 << pin_nr;
notpin = ~gpo->private->bitmask;
am335x_write32(base, AM335X_GPIO_REG_LEVELDETECT0,
am335x_read32(base, AM335X_GPIO_REG_LEVELDETECT0) & notpin);
am335x_write32(base, AM335X_GPIO_REG_LEVELDETECT1,
am335x_read32(base, AM335X_GPIO_REG_LEVELDETECT1) & notpin);
am335x_write32(base, AM335X_GPIO_REG_RISINGDETECT,
am335x_read32(base, AM335X_GPIO_REG_RISINGDETECT) & notpin);
am335x_write32(base, AM335X_GPIO_REG_FALLINGDETECT,
am335x_read32(base, AM335X_GPIO_REG_FALLINGDETECT) & notpin);
am335x_write32(base, AM335X_GPIO_REG_CLEARDATAOUT,
gpo->private->bitmask);
/* configure as output */
am335x_write32(base, AM335X_GPIO_REG_OE,
am335x_read32(base, AM335X_GPIO_REG_OE) & notpin);
gpo->calculate = gpo_calculate;
controller_block_add(gpo);
return gpo;
err_interm:
controller_block_free(gpo);
err_alloc:
err_rev:
munmap(base, AM335X_GPIO_SIZE);
return NULL;
}
......@@ -4,7 +4,9 @@ AM335X_TARGETS := $(LIBDIR)/libam335x.la
AM335X_BLOCKS := \
am335x_adc \
am335x_pwm \
am335x_qed
am335x_qed \
am335x_gpi \
am335x_gpo
AM335X_SRCS += $(addsuffix .c,$(addprefix $(DIR)/block_,$(AM335X_BLOCKS)))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment