/*
 * File      : gpio.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006, 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
 * 2011-01-13     weety		first version
 */

#include <rtthread.h>
#include "gpio.h"

#define GPIO0_BASE			(DAVINCI_GPIO_BASE + 0x10)
#define GPIO1_BASE			(DAVINCI_GPIO_BASE + 0x38)
#define GPIO2_BASE			(DAVINCI_GPIO_BASE + 0x60)
#define GPIO3_BASE			(DAVINCI_GPIO_BASE + 0x88)


static unsigned int dm365_gpio_base = (unsigned int)GPIO0_BASE;

#define GPIO_OE			(dm365_gpio_base + 0x00)
#define GPIO_DATAIN		(dm365_gpio_base + 0x10)
#define GPIO_DATAOUT		(dm365_gpio_base + 0x04)
#define GPIO_CLROUT		(dm365_gpio_base + 0x0C)
#define GPIO_SETOUT		(dm365_gpio_base + 0x08)

#define gpio_dirin(n)		*(volatile unsigned int *)((GPIO_OE)) |= 1<<(n)
#define gpio_dirout(n)	*(volatile unsigned int *)((GPIO_OE)) &= ~(1u<<(n))
#define gpio_set(n)		*(volatile unsigned int *)((GPIO_SETOUT)) = 1<<(n)
#define gpio_clr(n)		*(volatile unsigned int *)((GPIO_CLROUT)) = 1<<(n)
#define gpio_get(n)		( ( *(volatile unsigned int *)((GPIO_DATAIN)) & (1<<(n)) ) ? 1 : 0 )

 #define GPIO_GRP_MASK (5)
 
static int gpio_to_base(unsigned int gpio)
{
	unsigned int grp_idx;
	int ret;

	grp_idx = gpio >> GPIO_GRP_MASK;  

	switch (grp_idx) {
		case 0:
			dm365_gpio_base = (unsigned int)GPIO0_BASE;
			ret = 0;
			break;
		case 1:
			dm365_gpio_base = (unsigned int)GPIO1_BASE;
			ret = 0;
			break;
		case 2:
			dm365_gpio_base = (unsigned int)GPIO2_BASE;
			ret = 0;
			break;    
		case 3:
			dm365_gpio_base = (unsigned int)GPIO3_BASE;
			ret = 0;
			break;   
		default:
			ret =-RT_EIO;
			break;      
	}
	return ret;
}


int gpio_direction_input(unsigned int gpio)
{
	unsigned int offset;
	int ret=0;

	rt_ubase_t temp = rt_hw_interrupt_disable();
	ret = gpio_to_base(gpio); 
	if (ret < 0) {
		goto gpio_free;
	}
	offset =  gpio & ((1 << GPIO_GRP_MASK) -1);

	gpio_dirin(offset);

gpio_free:
	rt_hw_interrupt_enable(temp);

	return ret;
}

int gpio_direction_output(unsigned int gpio, int value)
{
	unsigned int offset;
	int ret=0;

	rt_ubase_t temp = rt_hw_interrupt_disable();
	ret = gpio_to_base(gpio); 
	if (ret < 0) {
		goto gpio_free;
	}

	offset =  gpio & ((1 << GPIO_GRP_MASK) -1);

	if (value) {
		gpio_set(offset);
	}
	else {
		gpio_clr(offset);
	}

	gpio_dirout(offset);

gpio_free:
	rt_hw_interrupt_enable(temp);

	return ret;
}

int  gpio_set_value(unsigned int gpio, int value)
{
	unsigned int offset;
	int ret=0;

	rt_ubase_t temp = rt_hw_interrupt_disable();
	ret = gpio_to_base(gpio); 
	if (ret < 0) {
		goto gpio_free;
	}

	offset =  gpio & ((1 << GPIO_GRP_MASK) -1);

	if (value) {
		gpio_set(offset);
	}
	else {
		gpio_clr(offset);
	}

gpio_free:
	rt_hw_interrupt_enable(temp);

	return ret;
}

int gpio_get_value(unsigned int gpio)
{
	unsigned int offset;
	int ret=0;

	rt_ubase_t temp = rt_hw_interrupt_disable();
	ret = gpio_to_base(gpio); 
	if (ret < 0) {
		goto gpio_free;
	}

	offset =  gpio & ((1 << GPIO_GRP_MASK) -1);
	ret = gpio_get(offset);

gpio_free:
	rt_hw_interrupt_enable(temp);

	return ret;
}