forked from Imagelibrary/rtems
272
bsps/shared/grlib/gpio/gpiolib.c
Normal file
272
bsps/shared/grlib/gpio/gpiolib.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/* GPIOLIB interface implementation
|
||||
*
|
||||
* COPYRIGHT (c) 2009.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <grlib/gpiolib.h>
|
||||
|
||||
#include <grlib/grlib_impl.h>
|
||||
|
||||
struct gpiolib_port;
|
||||
|
||||
struct gpiolib_port {
|
||||
struct gpiolib_port *next;
|
||||
int minor;
|
||||
struct gpiolib_drv *drv;
|
||||
void *handle;
|
||||
|
||||
int open;
|
||||
};
|
||||
|
||||
/* Root of GPIO Ports */
|
||||
struct gpiolib_port *gpiolib_ports;
|
||||
|
||||
/* Number of GPIO ports registered */
|
||||
static int port_nr;
|
||||
|
||||
/* 1 if libraray initialized */
|
||||
static int gpiolib_initied = 0;
|
||||
|
||||
/* Insert a port first in ports list */
|
||||
static void gpiolib_list_add(struct gpiolib_port *port)
|
||||
{
|
||||
port->next = gpiolib_ports;
|
||||
gpiolib_ports = port;
|
||||
}
|
||||
|
||||
static struct gpiolib_port *gpiolib_find(int minor)
|
||||
{
|
||||
struct gpiolib_port *p;
|
||||
|
||||
p = gpiolib_ports;
|
||||
while ( p && (p->minor != minor) ) {
|
||||
p = p->next;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct gpiolib_port *gpiolib_find_by_name(char *name)
|
||||
{
|
||||
struct gpiolib_port *p;
|
||||
struct gpiolib_info info;
|
||||
int (*get_info)(void *, struct gpiolib_info *);
|
||||
|
||||
p = gpiolib_ports;
|
||||
while ( p ) {
|
||||
get_info = p->drv->ops->get_info;
|
||||
if ( get_info && (get_info(p->handle, &info) == 0) ) {
|
||||
if ( strncmp(name, (char *)&info.devName[0], 64) == 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int gpiolib_drv_register(struct gpiolib_drv *drv, void *handle)
|
||||
{
|
||||
struct gpiolib_port *port;
|
||||
|
||||
if ( !drv || !drv->ops )
|
||||
return -1;
|
||||
|
||||
port = grlib_calloc(1, sizeof(*port));
|
||||
if ( port == NULL )
|
||||
return -1;
|
||||
|
||||
port->handle = handle;
|
||||
port->minor = port_nr++;
|
||||
port->drv = drv;
|
||||
|
||||
gpiolib_list_add(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpiolib_show(int port, void *handle)
|
||||
{
|
||||
struct gpiolib_port *p;
|
||||
|
||||
if ( port == -1 ) {
|
||||
p = gpiolib_ports;
|
||||
while (p != NULL) {
|
||||
if ( p->drv->ops->show )
|
||||
p->drv->ops->show(p->handle);
|
||||
p = p->next;
|
||||
}
|
||||
} else {
|
||||
if ( handle ) {
|
||||
p = handle;
|
||||
} else {
|
||||
p = gpiolib_find(port);
|
||||
}
|
||||
if ( p == NULL ) {
|
||||
printf("PORT %d NOT FOUND\n", port);
|
||||
return;
|
||||
}
|
||||
if ( p->drv->ops->show )
|
||||
p->drv->ops->show(p->handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void *gpiolib_open_internal(int port, char *devName)
|
||||
{
|
||||
struct gpiolib_port *p;
|
||||
|
||||
if ( gpiolib_initied == 0 )
|
||||
return NULL;
|
||||
|
||||
/* Find */
|
||||
if ( port >= 0 ) {
|
||||
p = gpiolib_find(port);
|
||||
} else {
|
||||
p = gpiolib_find_by_name(devName);
|
||||
}
|
||||
if ( p == NULL )
|
||||
return NULL;
|
||||
|
||||
if ( p->open )
|
||||
return NULL;
|
||||
|
||||
p->open = 1;
|
||||
return p;
|
||||
}
|
||||
|
||||
void *gpiolib_open(int port)
|
||||
{
|
||||
return gpiolib_open_internal(port, NULL);
|
||||
}
|
||||
|
||||
void *gpiolib_open_by_name(char *devName)
|
||||
{
|
||||
return gpiolib_open_internal(-1, devName);
|
||||
}
|
||||
|
||||
void gpiolib_close(void *handle)
|
||||
{
|
||||
struct gpiolib_port *p = handle;
|
||||
|
||||
if ( p && p->open ) {
|
||||
p->open = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int gpiolib_set_config(void *handle, struct gpiolib_config *cfg)
|
||||
{
|
||||
struct gpiolib_port *port = handle;
|
||||
|
||||
if ( !port || !cfg )
|
||||
return -1;
|
||||
|
||||
if ( !port->drv->ops->config )
|
||||
return -1;
|
||||
|
||||
return port->drv->ops->config(port->handle, cfg);
|
||||
}
|
||||
|
||||
int gpiolib_set(void *handle, int dir, int outval)
|
||||
{
|
||||
struct gpiolib_port *port = handle;
|
||||
|
||||
if ( !port )
|
||||
return -1;
|
||||
|
||||
if ( !port->drv->ops->set )
|
||||
return -1;
|
||||
|
||||
return port->drv->ops->set(port->handle, dir, outval);
|
||||
}
|
||||
|
||||
int gpiolib_get(void *handle, int *inval)
|
||||
{
|
||||
struct gpiolib_port *port = handle;
|
||||
|
||||
if ( !port || !inval)
|
||||
return -1;
|
||||
|
||||
if ( !port->drv->ops->get )
|
||||
return -1;
|
||||
|
||||
return port->drv->ops->get(port->handle, inval);
|
||||
}
|
||||
|
||||
/*** IRQ Functions ***/
|
||||
int gpiolib_irq_register(void *handle, void *func, void *arg)
|
||||
{
|
||||
struct gpiolib_port *port = handle;
|
||||
|
||||
if ( !port )
|
||||
return -1;
|
||||
|
||||
if ( !port->drv->ops->irq_register )
|
||||
return -1;
|
||||
|
||||
return port->drv->ops->irq_register(port->handle, func, arg);
|
||||
}
|
||||
|
||||
static int gpiolib_irq_opts(void *handle, unsigned int options)
|
||||
{
|
||||
struct gpiolib_port *port = handle;
|
||||
|
||||
if ( !port )
|
||||
return -1;
|
||||
|
||||
if ( !port->drv->ops->irq_opts )
|
||||
return -1;
|
||||
|
||||
return port->drv->ops->irq_opts(port->handle, options);
|
||||
}
|
||||
|
||||
int gpiolib_irq_clear(void *handle)
|
||||
{
|
||||
return gpiolib_irq_opts(handle, GPIOLIB_IRQ_CLEAR);
|
||||
}
|
||||
|
||||
int gpiolib_irq_force(void *handle)
|
||||
{
|
||||
return gpiolib_irq_opts(handle, GPIOLIB_IRQ_FORCE);
|
||||
}
|
||||
|
||||
int gpiolib_irq_enable(void *handle)
|
||||
{
|
||||
return gpiolib_irq_opts(handle, GPIOLIB_IRQ_ENABLE);
|
||||
}
|
||||
|
||||
int gpiolib_irq_disable(void *handle)
|
||||
{
|
||||
return gpiolib_irq_opts(handle, GPIOLIB_IRQ_DISABLE);
|
||||
}
|
||||
|
||||
int gpiolib_irq_mask(void *handle)
|
||||
{
|
||||
return gpiolib_irq_opts(handle, GPIOLIB_IRQ_MASK);
|
||||
}
|
||||
|
||||
int gpiolib_irq_unmask(void *handle)
|
||||
{
|
||||
return gpiolib_irq_opts(handle, GPIOLIB_IRQ_UNMASK);
|
||||
}
|
||||
|
||||
|
||||
/*** Initialization ***/
|
||||
int gpiolib_initialize(void)
|
||||
{
|
||||
if ( gpiolib_initied != 0 )
|
||||
return 0;
|
||||
|
||||
/* Initialize Libarary */
|
||||
port_nr = 0;
|
||||
gpiolib_ports = 0;
|
||||
gpiolib_initied = 1;
|
||||
return 0;
|
||||
}
|
||||
449
bsps/shared/grlib/gpio/grgpio.c
Normal file
449
bsps/shared/grlib/gpio/grgpio.c
Normal file
@@ -0,0 +1,449 @@
|
||||
/* GRGPIO GPIO Driver interface.
|
||||
*
|
||||
* COPYRIGHT (c) 2009.
|
||||
* Cobham Gaisler AB.
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <bsp.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <grlib/ambapp_bus.h>
|
||||
#include <grlib/grgpio.h>
|
||||
#include <grlib/gpiolib.h>
|
||||
#include <grlib/ambapp.h>
|
||||
#include <grlib/grlib.h>
|
||||
#include <grlib/grlib_impl.h>
|
||||
|
||||
/*#define DEBUG 1*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(x...) printk(x)
|
||||
#define STATIC
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#define STATIC static
|
||||
#endif
|
||||
|
||||
struct grgpio_isr {
|
||||
drvmgr_isr isr;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct grgpio_priv {
|
||||
struct drvmgr_dev *dev;
|
||||
struct grgpio_regs *regs;
|
||||
int irq;
|
||||
int minor;
|
||||
|
||||
/* Driver implementation */
|
||||
int port_cnt;
|
||||
unsigned char port_handles[32];
|
||||
struct grgpio_isr isrs[32];
|
||||
struct gpiolib_drv gpiolib_desc;
|
||||
unsigned int bypass;
|
||||
unsigned int imask;
|
||||
};
|
||||
|
||||
/******************* Driver Manager Part ***********************/
|
||||
|
||||
int grgpio_device_init(struct grgpio_priv *priv);
|
||||
|
||||
int grgpio_init1(struct drvmgr_dev *dev);
|
||||
int grgpio_init2(struct drvmgr_dev *dev);
|
||||
|
||||
struct drvmgr_drv_ops grgpio_ops =
|
||||
{
|
||||
.init = {grgpio_init1, NULL, NULL, NULL},
|
||||
.remove = NULL,
|
||||
.info = NULL
|
||||
};
|
||||
|
||||
struct amba_dev_id grgpio_ids[] =
|
||||
{
|
||||
{VENDOR_GAISLER, GAISLER_GPIO},
|
||||
{0, 0} /* Mark end of table */
|
||||
};
|
||||
|
||||
struct amba_drv_info grgpio_drv_info =
|
||||
{
|
||||
{
|
||||
DRVMGR_OBJ_DRV, /* Driver */
|
||||
NULL, /* Next driver */
|
||||
NULL, /* Device list */
|
||||
DRIVER_AMBAPP_GAISLER_GRGPIO_ID, /* Driver ID */
|
||||
"GRGPIO_DRV", /* Driver Name */
|
||||
DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
|
||||
&grgpio_ops,
|
||||
NULL, /* Funcs */
|
||||
0, /* No devices yet */
|
||||
0,
|
||||
},
|
||||
&grgpio_ids[0]
|
||||
};
|
||||
|
||||
void grgpio_register_drv (void)
|
||||
{
|
||||
DBG("Registering GRGPIO driver\n");
|
||||
drvmgr_drv_register(&grgpio_drv_info.general);
|
||||
}
|
||||
|
||||
/* Register GRGPIO pins as quick as possible to the GPIO library,
|
||||
* other drivers may depend upon them in INIT LEVEL 2.
|
||||
* Note that since IRQ may not be available in init1, it is assumed
|
||||
* that the GPIOLibrary does not request IRQ routines until LEVEL 2.
|
||||
*/
|
||||
int grgpio_init1(struct drvmgr_dev *dev)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int status, port;
|
||||
|
||||
DBG("GRGPIO[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
|
||||
|
||||
/* This core will not find other cores, but other driver may depend upon
|
||||
* the GPIO library to function. So, we set up GPIO right away.
|
||||
*/
|
||||
|
||||
/* Initialize library if not already done */
|
||||
status = gpiolib_initialize();
|
||||
if ( status < 0 )
|
||||
return DRVMGR_FAIL;
|
||||
|
||||
priv = dev->priv = grlib_calloc(1, sizeof(*priv));
|
||||
if ( !priv )
|
||||
return DRVMGR_NOMEM;
|
||||
priv->dev = dev;
|
||||
|
||||
if ( grgpio_device_init(priv) ) {
|
||||
free(dev->priv);
|
||||
dev->priv = NULL;
|
||||
return DRVMGR_FAIL;
|
||||
}
|
||||
|
||||
/* Register all ports available on this core as GPIO port to
|
||||
* upper layer
|
||||
*/
|
||||
for(port=0; port<priv->port_cnt; port++) {
|
||||
priv->port_handles[port] = port;
|
||||
gpiolib_drv_register(&priv->gpiolib_desc,
|
||||
&priv->port_handles[port]);
|
||||
}
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
/******************* Driver Implementation ***********************/
|
||||
|
||||
/* Find port from handle, returns -1 if not found */
|
||||
static int grgpio_find_port(void *handle, struct grgpio_priv **priv)
|
||||
{
|
||||
unsigned char portnr;
|
||||
|
||||
portnr = *(unsigned char *)handle;
|
||||
if ( portnr > 31 )
|
||||
return -1;
|
||||
*priv = (struct grgpio_priv *)
|
||||
(((unsigned int)handle - portnr*sizeof(unsigned char)) -
|
||||
offsetof(struct grgpio_priv, port_handles));
|
||||
return portnr;
|
||||
}
|
||||
|
||||
static int grgpio_gpiolib_open(void *handle)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
|
||||
return -1;
|
||||
}
|
||||
DBG("GRGPIO[0x%08x][%d]: OPENING\n", priv->regs, portnr);
|
||||
|
||||
/* Open the device, nothing to be done... */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grgpio_grpiolib_config(void *handle, struct gpiolib_config *cfg)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr;
|
||||
unsigned int mask;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
DBG("GRGPIO[0x%08x][%d]: CONFIG\n", priv->regs, portnr);
|
||||
|
||||
/* Configure the device. And check that operation is supported,
|
||||
* not all I/O Pins have IRQ support.
|
||||
*/
|
||||
mask = (1<<portnr);
|
||||
|
||||
/* Return error when IRQ not supported by this I/O Line and it
|
||||
* is beeing enabled by user.
|
||||
*/
|
||||
if ( ((mask & priv->imask) == 0) && cfg->mask )
|
||||
return -1;
|
||||
|
||||
priv->regs->imask &= ~mask; /* Disable interrupt temporarily */
|
||||
|
||||
/* Configure settings before enabling interrupt */
|
||||
priv->regs->ipol = (priv->regs->ipol & ~mask) | (cfg->irq_polarity ? mask : 0);
|
||||
priv->regs->iedge = (priv->regs->iedge & ~mask) | (cfg->irq_level ? 0 : mask);
|
||||
priv->regs->imask |= cfg->mask ? mask : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grgpio_grpiolib_get(void *handle, int *inval)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
DBG("GRGPIO[0x%08x][%d]: GET\n", priv->regs, portnr);
|
||||
|
||||
/* Get current status of the port */
|
||||
if ( inval )
|
||||
*inval = (priv->regs->data >> portnr) & 0x1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grgpio_grpiolib_irq_opts(void *handle, unsigned int options)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr;
|
||||
drvmgr_isr isr;
|
||||
void *arg;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
DBG("GRGPIO[0x%08x][%d]: IRQ OPTS 0x%x\n", priv->regs, portnr, options);
|
||||
|
||||
if ( options & GPIOLIB_IRQ_FORCE )
|
||||
return -1;
|
||||
|
||||
isr = priv->isrs[portnr].isr;
|
||||
arg = priv->isrs[portnr].arg;
|
||||
|
||||
if ( options & GPIOLIB_IRQ_DISABLE ) {
|
||||
/* Disable interrupt at interrupt controller */
|
||||
if ( drvmgr_interrupt_unregister(priv->dev, portnr, isr, arg) ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( options & GPIOLIB_IRQ_CLEAR ) {
|
||||
/* Clear interrupt at interrupt controller */
|
||||
if ( drvmgr_interrupt_clear(priv->dev, portnr) ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( options & GPIOLIB_IRQ_ENABLE ) {
|
||||
/* Enable interrupt at interrupt controller */
|
||||
if ( drvmgr_interrupt_register(priv->dev, portnr, "grgpio", isr, arg) ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( options & GPIOLIB_IRQ_MASK ) {
|
||||
/* Mask (disable) interrupt at interrupt controller */
|
||||
if ( drvmgr_interrupt_mask(priv->dev, portnr) ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( options & GPIOLIB_IRQ_UNMASK ) {
|
||||
/* Unmask (enable) interrupt at interrupt controller */
|
||||
if ( drvmgr_interrupt_unmask(priv->dev, portnr) ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grgpio_grpiolib_irq_register(void *handle, void *func, void *arg)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
|
||||
return -1;
|
||||
}
|
||||
DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
|
||||
|
||||
/* Since the user doesn't provide the ISR and argument, we must... */
|
||||
priv->isrs[portnr].isr = func;
|
||||
priv->isrs[portnr].arg = arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grgpio_grpiolib_set(void *handle, int dir, int outval)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr;
|
||||
unsigned int mask;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
|
||||
return -1;
|
||||
}
|
||||
DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
|
||||
|
||||
/* Set Direction and Output */
|
||||
mask = 1<<portnr;
|
||||
priv->regs->dir = (priv->regs->dir & ~mask) | (dir ? mask : 0);
|
||||
priv->regs->output = (priv->regs->output & ~mask) | (outval ? mask : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grgpio_gpiolib_show(void *handle)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr, i, regs[7];
|
||||
volatile unsigned int *reg;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
DBG("GRGPIO: FAILED SHOWING HANDLE 0x%08x\n", handle);
|
||||
return -1;
|
||||
}
|
||||
for (i=0, reg=&priv->regs->data; i<7; i++, reg++) {
|
||||
regs[i] = ( *reg >> portnr) & 1;
|
||||
}
|
||||
printf("GRGPIO[%p] PORT[%d]: IN/OUT/DIR: [%d,%d,%d], MASK/POL/EDGE: [%d,%d,%d], BYPASS: %d\n",
|
||||
priv->regs, portnr, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grgpio_gpiolib_get_info(void *handle, struct gpiolib_info *pinfo)
|
||||
{
|
||||
struct grgpio_priv *priv;
|
||||
int portnr;
|
||||
char prefix[48];
|
||||
struct drvmgr_dev *dev;
|
||||
|
||||
if ( !pinfo )
|
||||
return -1;
|
||||
|
||||
portnr = grgpio_find_port(handle, &priv);
|
||||
if ( portnr < 0 ) {
|
||||
DBG("GRGPIO: FAILED GET_INFO HANDLE 0x%08x\n", handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get Filesystem name prefix */
|
||||
dev = priv->dev;
|
||||
prefix[0] = '\0';
|
||||
if ( drvmgr_get_dev_prefix(dev, prefix) ) {
|
||||
/* Failed to get prefix, make sure of a unique FS name
|
||||
* by using the driver minor.
|
||||
*/
|
||||
snprintf(pinfo->devName, 64, "/dev/grgpio%d/%d", dev->minor_drv, portnr);
|
||||
} else {
|
||||
/* Got special prefix, this means we have a bus prefix
|
||||
* And we should use our "bus minor"
|
||||
*/
|
||||
snprintf(pinfo->devName, 64, "/dev/%sgrgpio%d/%d", prefix, dev->minor_bus, portnr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gpiolib_drv_ops grgpio_gpiolib_ops =
|
||||
{
|
||||
.config = grgpio_grpiolib_config,
|
||||
.get = grgpio_grpiolib_get,
|
||||
.irq_opts = grgpio_grpiolib_irq_opts,
|
||||
.irq_register = grgpio_grpiolib_irq_register,
|
||||
.open = grgpio_gpiolib_open,
|
||||
.set = grgpio_grpiolib_set,
|
||||
.show = grgpio_gpiolib_show,
|
||||
.get_info = grgpio_gpiolib_get_info,
|
||||
};
|
||||
|
||||
int grgpio_device_init(struct grgpio_priv *priv)
|
||||
{
|
||||
struct amba_dev_info *ambadev;
|
||||
struct ambapp_core *pnpinfo;
|
||||
union drvmgr_key_value *value;
|
||||
unsigned int mask;
|
||||
int port_cnt;
|
||||
|
||||
/* Get device information from AMBA PnP information */
|
||||
ambadev = (struct amba_dev_info *)priv->dev->businfo;
|
||||
if ( ambadev == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
pnpinfo = &ambadev->info;
|
||||
priv->irq = pnpinfo->irq;
|
||||
priv->regs = (struct grgpio_regs *)pnpinfo->apb_slv->start;
|
||||
|
||||
DBG("GRGPIO: 0x%08x irq %d\n", (unsigned int)priv->regs, priv->irq);
|
||||
|
||||
/* Mask all Interrupts */
|
||||
priv->regs->imask = 0;
|
||||
|
||||
/* Make IRQ Rising edge triggered default */
|
||||
priv->regs->ipol = 0xfffffffe;
|
||||
priv->regs->iedge = 0xfffffffe;
|
||||
|
||||
/* Read what I/O lines have IRQ support */
|
||||
priv->imask = priv->regs->ipol;
|
||||
|
||||
/* Let the user configure the port count, this might be needed
|
||||
* when the GPIO lines must not be changed (assigned during bootup)
|
||||
*/
|
||||
value = drvmgr_dev_key_get(priv->dev, "nBits", DRVMGR_KT_INT);
|
||||
if ( value ) {
|
||||
priv->port_cnt = value->i;
|
||||
} else {
|
||||
/* Auto detect number of GPIO ports */
|
||||
priv->regs->dir = 0;
|
||||
priv->regs->output = 0xffffffff;
|
||||
mask = priv->regs->output;
|
||||
priv->regs->output = 0;
|
||||
|
||||
for(port_cnt=0; port_cnt<32; port_cnt++)
|
||||
if ( (mask & (1<<port_cnt)) == 0 )
|
||||
break;
|
||||
priv->port_cnt = port_cnt;
|
||||
}
|
||||
|
||||
/* Let the user configure the BYPASS register, this might be needed
|
||||
* to select which cores can do I/O on a pin.
|
||||
*/
|
||||
value = drvmgr_dev_key_get(priv->dev, "bypass", DRVMGR_KT_INT);
|
||||
if ( value ) {
|
||||
priv->bypass = value->i;
|
||||
} else {
|
||||
priv->bypass = 0;
|
||||
}
|
||||
priv->regs->bypass = priv->bypass;
|
||||
|
||||
/* Prepare GPIOLIB layer */
|
||||
priv->gpiolib_desc.ops = &grgpio_gpiolib_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user