rt-thread/bsp/x1000/driver/drv_gpio.c

264 lines
6.9 KiB
C

/*
* File : drv_gpio.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2008 - 2016, RT-Thread Development Team
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2015-11-19 Urey the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "board.h"
#include "drv_gpio.h"
#define GPIO_DEBUG 0
#if GPIO_DEBUG
#define GPIO_DBG(...) rt_kprintf(__VA_ARGS__)
#else
#define GPIO_DBG(...)
#endif
struct jz_gpio_irq_def _g_gpio_irq_tbl[GPIO_NR_PORTS] = {0};
rt_inline int _fls(int x)
{
__asm__("clz %0, %1" : "=r" (x) : "r" (x));
return 32 - x;
}
void gpio_set_func(enum gpio_port port, uint32_t pins, enum gpio_function func)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
writel(func & 0x8 ? pins : 0, GPIO_PXINTS(port));
writel(func & 0x4 ? pins : 0, GPIO_PXMSKS(port));
writel(func & 0x2 ? pins : 0, GPIO_PXPAT1S(port));
writel(func & 0x1 ? pins : 0, GPIO_PXPAT0S(port));
writel(func & 0x8 ? 0 : pins, GPIO_PXINTC(port));
writel(func & 0x4 ? 0 : pins, GPIO_PXMSKC(port));
writel(func & 0x2 ? 0 : pins, GPIO_PXPAT1C(port));
writel(func & 0x1 ? 0 : pins, GPIO_PXPAT0C(port));
writel(func & 0x10 ? pins : 0, GPIO_PXPENC(port));
writel(func & 0x10 ? 0 : pins, GPIO_PXPENS(port));
}
void gpio_set_value(enum gpio_port port,enum gpio_pin pin,int value)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
if (value)
writel(pin, GPIO_PXPAT0S(port));
else
writel(pin, GPIO_PXPAT0C(port));
}
void gpio_enable_pull(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
writel(pin, GPIO_PXPENC(port));
}
void gpio_disable_pull(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
writel(pin, GPIO_PXPENS(port));
}
void gpio_ctrl_pull(enum gpio_port port, uint32_t pins,int enable)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
if (enable)
writel(pins, GPIO_PXPENC(port));
else
writel(pins, GPIO_PXPENS(port));
}
int gpio_get_value(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
return !!(readl(GPIO_PXPIN(port)) & pin);
}
int gpio_get_flag(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
return (readl(GPIO_PXFLG(port)) & pin);
}
void gpio_clear_flag(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
writel(pin, GPIO_PXFLGC(port));
}
void gpio_direction_input(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
gpio_set_func(port,pin,GPIO_INPUT);
}
void gpio_direction_output(enum gpio_port port, enum gpio_pin pin,int value)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
gpio_set_func(port, pin, value ? GPIO_OUTPUT1 : GPIO_OUTPUT0);
}
/*********************************************************************************************************
** IRQ
*********************************************************************************************************/
void gpio_unmask_irq(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
writel(pin, GPIO_PXMSKC(port));
}
void gpio_mask_irq(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
writel(BIT(pin), GPIO_PXMSKS(port));
}
int gpio_set_irq_type(enum gpio_port port, enum gpio_pin pin, enum gpio_irq_type irq_type)
{
enum gpio_function func;
RT_ASSERT(IS_GPIO_ALL_PORT(port));
if (irq_type & IRQ_TYPE_PROBE)
return 0;
switch (irq_type & IRQ_TYPE_SENSE_MASK)
{
case IRQ_TYPE_LEVEL_HIGH:
func = GPIO_INT_HI;
break;
case IRQ_TYPE_LEVEL_LOW:
func = GPIO_INT_LO;
break;
case IRQ_TYPE_EDGE_RISING:
func = GPIO_INT_RE;
break;
case IRQ_TYPE_EDGE_FALLING:
func = GPIO_INT_FE;
break;
case IRQ_TYPE_EDGE_BOTH:
if (gpio_get_value(port, pin))
func = GPIO_INT_FE;
else
func = GPIO_INT_RE;
break;
default:
return -1;
}
gpio_set_func(port,pin, func);
return 0;
}
void gpio_ack_irq(enum gpio_port port, enum gpio_pin pin)
{
RT_ASSERT(IS_GPIO_ALL_PORT(port));
writel(pin, GPIO_PXFLGC(port));
}
void gpio_set_irq_callback(enum gpio_port port, enum gpio_pin pin, void (*irq_cb)(void *),void *irq_arg)
{
uint32_t pin_id;
RT_ASSERT(IS_GPIO_ALL_PORT(port));
pin_id = _fls(pin) - 1;
GPIO_DBG("port = %d,pin = %d \n",port,pin_id);
_g_gpio_irq_tbl[port].irq_cb[pin_id] = irq_cb;
_g_gpio_irq_tbl[port].irq_arg[pin_id] = irq_arg;
GPIO_DBG("set irq callback end... \n");
}
void gpio_irq_handler(int irq, void *param)
{
struct jz_gpio_irq_def *irq_def = (struct jz_gpio_irq_def *)param;
uint32_t pend,mask;
uint32_t pin_id;
enum gpio_port port = (IRQ_GPIO0 - irq);
enum gpio_pin pin;
RT_ASSERT(param != RT_NULL);
GPIO_DBG("GPIO irq handler,irq=%d\n",irq);
pend = readl(GPIO_PXFLG(port));
mask = readl(GPIO_PXMSK(port));
GPIO_DBG("port =%d pend =%08x mask =%08x\n",port,pend,mask);
pend = pend & ~mask;
while(pend)
{
pin_id = _fls(pend) - 1;
pin = 0x01 << pin_id;
GPIO_DBG("PORT%d PIN%d interrupt happened..\n",port,pin_id);
if(irq_def->irq_cb[pin_id] != RT_NULL)
{
GPIO_DBG("do irq callback...\n",port,pin);
irq_def->irq_cb[pin_id](irq_def->irq_arg[pin_id]);
}
pend &= ~(0x01 << pin_id);
gpio_ack_irq(port, pin);
}
}
int rt_hw_gpio_init(void)
{
GPIO_DBG("Install gpio interrupt source...\n");
/* install ISR */
rt_hw_interrupt_install(IRQ_GPIO0,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_A],"GPIOAINT");
rt_hw_interrupt_umask(IRQ_GPIO0);
rt_hw_interrupt_install(IRQ_GPIO1,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_B],"GPIOBINT");
rt_hw_interrupt_umask(IRQ_GPIO1);
rt_hw_interrupt_install(IRQ_GPIO2,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_C],"GPIOCINT");
rt_hw_interrupt_umask(IRQ_GPIO2);
rt_hw_interrupt_install(IRQ_GPIO3,gpio_irq_handler,&_g_gpio_irq_tbl[GPIO_PORT_D],"GPIODINT");
rt_hw_interrupt_umask(IRQ_GPIO3);
return 0;
}
INIT_BOARD_EXPORT(rt_hw_gpio_init);