/*
 * (C) Copyright 2007-2013
 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
 * Jerry Wang <wangflord@allwinnertech.com>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */
#include <common.h>
#include <malloc.h>
#include <asm/io.h>
#include <sys_config.h>
#include <fdt_support.h>

DECLARE_GLOBAL_DATA_PTR;


//#define GPIO_REG_READ(reg)              smc_readl((reg))
//#define GPIO_REG_WRITE(reg, value)      smc_writel((value), (reg))

#define GPIO_REG_READ(reg)              (readl((reg)))
#define GPIO_REG_WRITE(reg, value)      writel((value), (reg))
/* #define GPIO_REG_WRITE(reg, value)      {tick_printf("line:%d %s reg:0x%x value:0x%x\n", __LINE__, __func__, reg, value);  writel((value), (reg));} */


/**#############################################################################################################
 *
 *                           GPIO(PIN) Operations
 *
-##############################################################################################################*/
#ifdef CONFIG_SUNXI_GPIO_V2
#define PIOC_REG_o_CFG0                 (0x00)
#define PIOC_REG_o_CFG1                 (0x04)
#define PIOC_REG_o_CFG2                 (0x08)
#define PIOC_REG_o_CFG3                 (0x0C)
#define PIOC_REG_o_DATA                 (0x10)
#define PIOC_REG_o_DRV0                 (0x14)
#define PIOC_REG_o_DRV1                 (0x18)
#define PIOC_REG_o_DRV2                 (0x1C)
#define PIOC_REG_o_DRV3                 (0x20)
#define PIOC_REG_o_PUL0                 (0x24)
#define PIOC_REG_o_PUL1                 (0x28)
#define PIOC_o_OFFSET										(0x30)
#define PIOC_o_DLEVEL			(8)
#define PIO_CFG_MASK			(0x0f)
#else
#define PIOC_REG_o_CFG0                 (0x00)
#define PIOC_REG_o_CFG1                 (0x04)
#define PIOC_REG_o_CFG2                 (0x08)
#define PIOC_REG_o_CFG3                 (0x0C)
#define PIOC_REG_o_DATA                 (0x10)
#define PIOC_REG_o_DRV0                 (0x14)
#define PIOC_REG_o_DRV1                 (0x18)
#define PIOC_REG_o_PUL0                 (0x1C)
#define PIOC_REG_o_PUL1                 (0x20)
#define PIO_CFG_MASK			(0x07)
#define PIOC_o_OFFSET										(0x24)
#define PIOC_o_DLEVEL			(16)
#endif

#define _PIO_REG_CFG(n, i) \
		((volatile unsigned int *)((unsigned long)SUNXI_PIO_BASE + \
		((n)-1) * PIOC_o_OFFSET + ((i)<<2) + PIOC_REG_o_CFG0))
#define _PIO_REG_DLEVEL(n, i) \
		((volatile unsigned int *)((unsigned long)SUNXI_PIO_BASE + \
		((n)-1) * PIOC_o_OFFSET + ((i)<<2) + PIOC_REG_o_DRV0))
#define _PIO_REG_PULL(n, i) \
		((volatile unsigned int *)((unsigned long)SUNXI_PIO_BASE + \
		((n)-1) * PIOC_o_OFFSET + ((i)<<2) + PIOC_REG_o_PUL0))
#define _PIO_REG_DATA(n) \
		((volatile unsigned int *)((unsigned long)SUNXI_PIO_BASE + \
		((n)-1) * PIOC_o_OFFSET + PIOC_REG_o_DATA))

#define _PIO_REG_CFG_VALUE(n, i) \
		readl(IOMEM_ADDR(SUNXI_PIO_BASE + ((n)-1) * PIOC_o_OFFSET + ((i)<<2) + PIOC_REG_o_CFG0))
#define _PIO_REG_DLEVEL_VALUE(n, i) \
		readl(IOMEM_ADDR(SUNXI_PIO_BASE + ((n)-1) * PIOC_o_OFFSET + ((i)<<2) + PIOC_REG_o_DRV0))
#define _PIO_REG_PULL_VALUE(n, i) \
		readl(IOMEM_ADDR(SUNXI_PIO_BASE + ((n)-1) * PIOC_o_OFFSET + ((i)<<2) + PIOC_REG_o_PUL0))
#define _PIO_REG_DATA_VALUE(n) \
		readl(IOMEM_ADDR(SUNXI_PIO_BASE + ((n)-1) * PIOC_o_OFFSET + PIOC_REG_o_DATA))
#define _PIO_REG_BASE(n) \
		((volatile unsigned int *)((unsigned long)SUNXI_PIO_BASE +((n)-1) * PIOC_o_OFFSET))

#ifdef SUNXI_R_PIO_BASE
#define _R_PIO_REG_CFG(n, i)                                                   \
	((volatile unsigned int *)((unsigned long)SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET +        \
				   ((i) << 2) + PIOC_REG_o_CFG0))
#define _R_PIO_REG_DLEVEL(n, i)                                                \
	((volatile unsigned int *)((unsigned long)SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET +        \
				   ((i) << 2) + PIOC_REG_o_DRV0))
#define _R_PIO_REG_PULL(n, i)                                                  \
	((volatile unsigned int *)((unsigned long)SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET +        \
				   ((i) << 2) + PIOC_REG_o_PUL0))
#define _R_PIO_REG_DATA(n)                                                     \
	((volatile unsigned int *)((unsigned long)SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET + PIOC_REG_o_DATA))

#define _R_PIO_REG_CFG_VALUE(n, i)                                             \
		readl(IOMEM_ADDR(SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET + ((i) << 2) + PIOC_REG_o_CFG0))
#define _R_PIO_REG_DLEVEL_VALUE(n, i)                                          \
		readl(IOMEM_ADDR(SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET + ((i) << 2) + PIOC_REG_o_DRV0))
#define _R_PIO_REG_PULL_VALUE(n, i)                                            \
		readl(IOMEM_ADDR(SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET + ((i) << 2) + PIOC_REG_o_PUL0))
#define _R_PIO_REG_DATA_VALUE(n)                                               \
		readl(IOMEM_ADDR(SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET + PIOC_REG_o_DATA))
#define _R_PIO_REG_BASE(n)                                                     \
		((volatile unsigned int *)((unsigned long)SUNXI_R_PIO_BASE + ((n)-12) * PIOC_o_OFFSET))

volatile void* PIO_REG_CFG(int port, int port_num)
{
	if(port < 12)
	{
		return _PIO_REG_CFG(port, port_num);
	}
	else
	{
		return _R_PIO_REG_CFG(port, port_num);
	}
}

volatile void* PIO_REG_PULL(int port, int port_num)
{
	if(port < 12)
	{
		return _PIO_REG_PULL(port, port_num);  
	}
	else
	{
		return _R_PIO_REG_PULL(port, port_num);  
	}
}

volatile void* PIO_REG_DLEVEL(int port,int port_num)
{
	if(port < 12)
	{
		return _PIO_REG_DLEVEL(port, port_num);
	}
	else
	{
		return _R_PIO_REG_DLEVEL(port, port_num);
	}
}

volatile void* PIO_REG_DATA(int port)
{
	if(port < 12)
	{
		return _PIO_REG_DATA(port);
	}
	else
	{
		return _R_PIO_REG_DATA(port);
	}
}

u32 PIO_REG_CFG_VALUE(uint port, uint i)  
{
	u32 value = 0;
	if( port < 12) 
	{
		value =  _PIO_REG_CFG_VALUE(port,i);
	}
	else
	{
		value = _R_PIO_REG_CFG_VALUE(port,i);
	}
	return value;
}

u32 PIO_REG_DLEVEL_VALUE(uint port, uint i)  
{
	u32 value = 0;
	if( port < 12) 
	{
		value =  _R_PIO_REG_DLEVEL_VALUE(port,i);
	}
	else
	{
		value = _R_PIO_REG_DLEVEL_VALUE(port,i);
	}
	return value;
}

u32 PIO_REG_PULL_VALUE(uint port, uint i)  
{
	u32 value = 0;
	if( port < 12) 
	{
		value =  _PIO_REG_PULL_VALUE(port,i);
	}
	else
	{
		value = _R_PIO_REG_PULL_VALUE(port,i);
	}
	return value;
}

u32 PIO_REG_DATA_VALUE(uint port)  
{
	u32 value = 0;
	if( port < 12) 
	{
		value =  _PIO_REG_DATA_VALUE(port);
	}
	else
	{
		value = _R_PIO_REG_DATA_VALUE(port);
	}
	return value;
}
#else
volatile void* PIO_REG_CFG(int port, int port_num)
{
	return _PIO_REG_CFG(port, port_num);
}

volatile void* PIO_REG_PULL(int port, int port_num)
{
	return _PIO_REG_PULL(port, port_num);  
}

volatile void* PIO_REG_DLEVEL(int port,int port_num)
{
	
	return _PIO_REG_DLEVEL(port, port_num);
	
}

volatile void* PIO_REG_DATA(int port)
{
	return _PIO_REG_DATA(port);
}

u32 PIO_REG_CFG_VALUE(uint port, uint i)  
{
	return _PIO_REG_CFG_VALUE(port,i);
}

u32 PIO_REG_DLEVEL_VALUE(uint port, uint i)  
{
	return _PIO_REG_DLEVEL_VALUE(port,i);
}

u32 PIO_REG_PULL_VALUE(uint port, uint i)  
{
	return _PIO_REG_PULL_VALUE(port,i);
}

u32 PIO_REG_DATA_VALUE(uint port)  
{
        return _PIO_REG_DATA_VALUE(port);
}
#endif




#define PIO_REG_BASE(n)                    ((volatile unsigned int *)(SUNXI_PIO_BASE +((n)-1)*24))

__s32  gpio_get_all_pin_status(ulong p_handler, user_gpio_set_t *gpio_status, __u32 gpio_count_max, __u32 if_get_from_hardware)
{
    char               *tmp_buf;
    __u32               group_count_max, first_port;      
    system_gpio_set_t  *user_gpio_set, *tmp_sys_gpio_data;
    user_gpio_set_t  *script_gpio;
    __u32               port_num_func, port_num_pull;
    volatile __u32     *tmp_group_func_addr = NULL, *tmp_group_pull_addr;
    volatile __u32     *tmp_group_data_addr, *tmp_group_dlevel_addr;
    __u32               port, port_num;
    __u32               pre_port = 0x7fffffff, pre_port_num_func = 0x7fffffff, pre_port_num_pull = 0x7fffffff;
    __u32               i;

    if((!p_handler) || (!gpio_status))
    {
        return EGPIO_FAIL;
    }
    if(gpio_count_max <= 0)
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    if(group_count_max <= 0)
    {
        return EGPIO_FAIL;
    }
    user_gpio_set = (system_gpio_set_t *)(tmp_buf + 16);
    if(group_count_max > gpio_count_max)
    {
        group_count_max = gpio_count_max;
    }
 
    if(!if_get_from_hardware)
    {
        for(i = 0; i < group_count_max; i++)
        {
            tmp_sys_gpio_data = user_gpio_set + i;
            script_gpio       = gpio_status + i; 

            script_gpio->port      = tmp_sys_gpio_data->port;
            script_gpio->port_num  = tmp_sys_gpio_data->port_num;     
            script_gpio->pull      = tmp_sys_gpio_data->user_gpio_status.pull;
            script_gpio->mul_sel   = tmp_sys_gpio_data->user_gpio_status.mul_sel;
            script_gpio->drv_level = tmp_sys_gpio_data->user_gpio_status.drv_level;
            script_gpio->data      = tmp_sys_gpio_data->user_gpio_status.data;
            strcpy(script_gpio->gpio_name, tmp_sys_gpio_data->gpio_name);
        }
    }
    else
    {
        for(first_port = 0; first_port < group_count_max; first_port++)
        {
            tmp_sys_gpio_data  = user_gpio_set + first_port;
            port     = tmp_sys_gpio_data->port;
            port_num = tmp_sys_gpio_data->port_num;
            if(!port)
            {
                continue;
            }
            port_num_func = (port_num >> 3);
            port_num_pull = (port_num >> 4);
            tmp_group_func_addr    = PIO_REG_CFG(port, port_num_func);
            tmp_group_pull_addr    = PIO_REG_PULL(port, port_num_pull);
            tmp_group_dlevel_addr  = PIO_REG_DLEVEL(port, port_num_pull);
            tmp_group_data_addr    = PIO_REG_DATA(port);
            break;
        }
        if(first_port >= group_count_max)
        {
            return 0;
        }
        for(i = first_port; i < group_count_max; i++)
        {
            tmp_sys_gpio_data = user_gpio_set + i; 
            script_gpio       = gpio_status + i;  

            port     = tmp_sys_gpio_data->port;
            port_num = tmp_sys_gpio_data->port_num;

            script_gpio->port = port; 
            script_gpio->port_num  = port_num;
            strcpy(script_gpio->gpio_name, tmp_sys_gpio_data->gpio_name);

            port_num_func = (port_num >> 3);
            port_num_pull = (port_num >> 4);

            if((port_num_pull != pre_port_num_pull) || (port != pre_port))
            {
                tmp_group_func_addr    = PIO_REG_CFG(port, port_num_func);
                tmp_group_pull_addr    = PIO_REG_PULL(port, port_num_pull);
                tmp_group_dlevel_addr  = PIO_REG_DLEVEL(port, port_num_pull);
                tmp_group_data_addr    = PIO_REG_DATA(port);               
            }
            else if(pre_port_num_func != port_num_func)   
            {
                tmp_group_func_addr    = PIO_REG_CFG(port, port_num_func);
            }

            pre_port_num_pull = port_num_pull;
            pre_port_num_func = port_num_func;
            pre_port          = port;
          
            script_gpio->pull      = (GPIO_REG_READ(tmp_group_pull_addr)   >> ((port_num - (port_num_pull<<4))<<1)) & 0x03; 
            script_gpio->drv_level = (GPIO_REG_READ(tmp_group_dlevel_addr) >> ((port_num - (port_num_pull<<4))<<1)) & 0x03;
            script_gpio->mul_sel   = (GPIO_REG_READ(tmp_group_func_addr)   >> ((port_num - (port_num_func<<3))<<2)) & PIO_CFG_MASK;
            if(script_gpio->mul_sel <= 1)
            {
                script_gpio->data  = (GPIO_REG_READ(tmp_group_data_addr)   >>   port_num) & 0x01;  
            }
            else
            {
                script_gpio->data = -1;
            }
        }
    }

    return EGPIO_SUCCESS;
}



__s32  gpio_get_one_pin_status(ulong p_handler, user_gpio_set_t *gpio_status, const char *gpio_name, __u32 if_get_from_hardware)
{
    char               *tmp_buf;                                     
    __u32               group_count_max;                               
    system_gpio_set_t  *user_gpio_set, *tmp_sys_gpio_data;
    __u32               port_num_func, port_num_pull;
    __u32               port, port_num;
    __u32               i, tmp_val1, tmp_val2;

   
    if((!p_handler) || (!gpio_status))
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    if(group_count_max <= 0)
    {
        return EGPIO_FAIL;
    }
    else if((group_count_max > 1) && (!gpio_name))
    {
        return EGPIO_FAIL;
    }
    user_gpio_set = (system_gpio_set_t *)(tmp_buf + 16);

    for(i = 0; i < group_count_max; i++)
    {
        tmp_sys_gpio_data = user_gpio_set + i; 
        if(strcmp(gpio_name, tmp_sys_gpio_data->gpio_name))
        {
            continue;
        }
        strcpy(gpio_status->gpio_name, tmp_sys_gpio_data->gpio_name);
        port                   = tmp_sys_gpio_data->port;
        port_num               = tmp_sys_gpio_data->port_num;
        gpio_status->port      = port;                                         
        gpio_status->port_num  = port_num;                                     

        if(!if_get_from_hardware)                                                
        {
            gpio_status->mul_sel   = tmp_sys_gpio_data->user_gpio_status.mul_sel;  
            gpio_status->pull      = tmp_sys_gpio_data->user_gpio_status.pull;   
            gpio_status->drv_level = tmp_sys_gpio_data->user_gpio_status.drv_level;
            gpio_status->data      = tmp_sys_gpio_data->user_gpio_status.data;  
        }
        else                                                                  
        {
			port_num_func = (port_num >> 3);
			port_num_pull = (port_num >> 4);

			tmp_val1 = ((port_num - (port_num_func << 3)) << 2);
			tmp_val2 = ((port_num - (port_num_pull << 4)) << 1);
			gpio_status->mul_sel   = (PIO_REG_CFG_VALUE(port, port_num_func)>>tmp_val1) & PIO_CFG_MASK;
			gpio_status->pull      = (PIO_REG_PULL_VALUE(port, port_num_pull)>>tmp_val2) & 0x03;    
			gpio_status->drv_level = (PIO_REG_DLEVEL_VALUE(port, port_num_pull)>>tmp_val2) & 0x03;    
			if(gpio_status->mul_sel <= 1)
			{
				gpio_status->data = (PIO_REG_DATA_VALUE(port) >> port_num) & 0x01;  
			}
			else
			{
				gpio_status->data = -1;
			}
        }

        break;
    }

    return EGPIO_SUCCESS;
}

__s32  gpio_set_one_pin_status(ulong p_handler, user_gpio_set_t *gpio_status, const char *gpio_name, __u32 if_set_to_current_input_status)
{
    char               *tmp_buf;                                   
    __u32               group_count_max;                            
    system_gpio_set_t  *user_gpio_set, *tmp_sys_gpio_data;
    user_gpio_set_t     script_gpio;
    volatile __u32     *tmp_addr;
    __u32               port_num_func, port_num_pull;
    __u32               port, port_num;
    __u32               i, reg_val, tmp_val;

  
    if((!p_handler) || (!gpio_name))
    {
        return EGPIO_FAIL;
    }
    if((if_set_to_current_input_status) && (!gpio_status))
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    if(group_count_max <= 0)
    {
        return EGPIO_FAIL;
    }
    user_gpio_set = (system_gpio_set_t *)(tmp_buf + 16);
 
    for(i = 0; i < group_count_max; i++)
    {
        tmp_sys_gpio_data = user_gpio_set + i;  
        if(strcmp(gpio_name, tmp_sys_gpio_data->gpio_name))
        {
            continue;
        }

        port          = tmp_sys_gpio_data->port;            
        port_num      = tmp_sys_gpio_data->port_num;      
        port_num_func = (port_num >> 3);
        port_num_pull = (port_num >> 4);

        if(if_set_to_current_input_status)                                
        {
            
            script_gpio.mul_sel   = gpio_status->mul_sel;
            script_gpio.pull      = gpio_status->pull;
            script_gpio.drv_level = gpio_status->drv_level;
            script_gpio.data      = gpio_status->data;
        }
        else
        {
            script_gpio.mul_sel   = tmp_sys_gpio_data->user_gpio_status.mul_sel;
            script_gpio.pull      = tmp_sys_gpio_data->user_gpio_status.pull;
            script_gpio.drv_level = tmp_sys_gpio_data->user_gpio_status.drv_level;
            script_gpio.data      = tmp_sys_gpio_data->user_gpio_status.data;
        }

        if(script_gpio.mul_sel >= 0)
        {
            tmp_addr = PIO_REG_CFG(port, port_num_func);
            reg_val = GPIO_REG_READ(tmp_addr);                                                      
            tmp_val = (port_num - (port_num_func<<3))<<2;
            reg_val &= ~(PIO_CFG_MASK << tmp_val);
            reg_val |=  (script_gpio.mul_sel) << tmp_val;
            GPIO_REG_WRITE(tmp_addr, reg_val);
        }
       
        if(script_gpio.pull >= 0)
        {
            tmp_addr = PIO_REG_PULL(port, port_num_pull);
            reg_val = GPIO_REG_READ(tmp_addr);                                                 
            tmp_val = (port_num - (port_num_pull<<4))<<1;
            reg_val &= ~(0x03 << tmp_val);
            reg_val |=  (script_gpio.pull) << tmp_val;
            GPIO_REG_WRITE(tmp_addr, reg_val);
        }
      
        if(script_gpio.drv_level >= 0)
        {
            tmp_addr = PIO_REG_DLEVEL(port, port_num_pull);
            reg_val = GPIO_REG_READ(tmp_addr);                                                
            tmp_val = (port_num - (port_num_pull<<4))<<1;
            reg_val &= ~(0x03 << tmp_val);
            reg_val |=  (script_gpio.drv_level) << tmp_val;
            GPIO_REG_WRITE(tmp_addr, reg_val);
        }

        if(script_gpio.mul_sel == 1)
        {
            if(script_gpio.data >= 0)
            {
                tmp_addr = PIO_REG_DATA(port);
                reg_val = GPIO_REG_READ(tmp_addr);                                                 
                reg_val &= ~(0x01 << port_num);
                reg_val |=  (script_gpio.data & 0x01) << port_num;
                GPIO_REG_WRITE(tmp_addr, reg_val);
            }
        }

        break;
    }

    return EGPIO_SUCCESS;
}

__s32  gpio_set_one_pin_io_status(ulong p_handler, __u32 if_set_to_output_status, const char *gpio_name)
{
    char               *tmp_buf;                                       
    __u32               group_count_max;                             
    system_gpio_set_t  *user_gpio_set = NULL, *tmp_sys_gpio_data;
    volatile __u32      *tmp_group_func_addr = NULL;
    __u32               port, port_num, port_num_func;
    __u32                i, reg_val;

   
    if(!p_handler)
    {
        return EGPIO_FAIL;
    }
    if(if_set_to_output_status > 1)
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    tmp_sys_gpio_data = (system_gpio_set_t *)(tmp_buf + 16);
    if(group_count_max == 0)
    {
        return EGPIO_FAIL;
    }
    else if(group_count_max == 1)
    {
        user_gpio_set = tmp_sys_gpio_data;
    }
    else if(gpio_name)
    {
        for(i=0; i<group_count_max; i++)
        {
            if(strcmp(gpio_name, tmp_sys_gpio_data->gpio_name))
            {
                tmp_sys_gpio_data ++;
                continue;
            }
            user_gpio_set = tmp_sys_gpio_data;
            break;
        }
    }
    if(!user_gpio_set)
    {
        return EGPIO_FAIL;
    }

    port     = user_gpio_set->port;
    port_num = user_gpio_set->port_num;
    port_num_func = port_num >> 3;

    tmp_group_func_addr = PIO_REG_CFG(port, port_num_func);
    reg_val = GPIO_REG_READ(tmp_group_func_addr);
    reg_val &= ~(PIO_CFG_MASK << (((port_num - (port_num_func<<3))<<2)));
    reg_val |=   if_set_to_output_status << (((port_num - (port_num_func<<3))<<2));
    GPIO_REG_WRITE(tmp_group_func_addr, reg_val);

    return EGPIO_SUCCESS;
}

__s32  gpio_set_one_pin_pull(ulong p_handler, __u32 set_pull_status, const char *gpio_name)
{
    char               *tmp_buf;                                      
    __u32               group_count_max;                             
    system_gpio_set_t  *user_gpio_set = NULL, *tmp_sys_gpio_data;
    volatile __u32      *tmp_group_pull_addr = NULL;
    __u32               port, port_num, port_num_pull;
    __u32                i, reg_val;
    
    if(!p_handler)
    {
        return EGPIO_FAIL;
    }
    if(set_pull_status >= 4)
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    tmp_sys_gpio_data = (system_gpio_set_t *)(tmp_buf + 16);
    if(group_count_max == 0)
    {
        return EGPIO_FAIL;
    }
    else if(group_count_max == 1)
    {
        user_gpio_set = tmp_sys_gpio_data;
    }
    else if(gpio_name)
    {
        for(i=0; i<group_count_max; i++)
        {
            if(strcmp(gpio_name, tmp_sys_gpio_data->gpio_name))
            {
                tmp_sys_gpio_data ++;
                continue;
            }
            user_gpio_set = tmp_sys_gpio_data;
            break;
        }
    }
    if(!user_gpio_set)
    {
        return EGPIO_FAIL;
    }

    port     = user_gpio_set->port;
    port_num = user_gpio_set->port_num;
    port_num_pull = port_num >> 4;

    tmp_group_pull_addr = PIO_REG_PULL(port, port_num_pull);
    reg_val = GPIO_REG_READ(tmp_group_pull_addr);
    reg_val &= ~(0x03 << (((port_num - (port_num_pull<<4))<<1)));
    reg_val |=  (set_pull_status << (((port_num - (port_num_pull<<4))<<1)));
    GPIO_REG_WRITE(tmp_group_pull_addr, reg_val);

    return EGPIO_SUCCESS;
}

__s32  gpio_set_one_pin_driver_level(ulong p_handler, __u32 set_driver_level, const char *gpio_name)
{
    char               *tmp_buf;                                      
    __u32               group_count_max;                            
    system_gpio_set_t  *user_gpio_set = NULL, *tmp_sys_gpio_data;
    volatile __u32      *tmp_group_dlevel_addr = NULL;
    __u32               port, port_num, port_num_dlevel;
    __u32                i, reg_val;
   
    if(!p_handler)
    {
        return EGPIO_FAIL;
    }
    if(set_driver_level >= 4)
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    tmp_sys_gpio_data = (system_gpio_set_t *)(tmp_buf + 16);

    if(group_count_max == 0)
    {
        return EGPIO_FAIL;
    }
    else if(group_count_max == 1)
    {
        user_gpio_set = tmp_sys_gpio_data;
    }
    else if(gpio_name)
    {
        for(i=0; i<group_count_max; i++)
        {
            if(strcmp(gpio_name, tmp_sys_gpio_data->gpio_name))
            {
                tmp_sys_gpio_data ++;
                continue;
            }
            user_gpio_set = tmp_sys_gpio_data;
            break;
        }
    }
    if(!user_gpio_set)
    {
        return EGPIO_FAIL;
    }

    port     = user_gpio_set->port;
    port_num = user_gpio_set->port_num;
    port_num_dlevel = port_num >> 4;

    tmp_group_dlevel_addr = PIO_REG_DLEVEL(port, port_num_dlevel);
    reg_val = GPIO_REG_READ(tmp_group_dlevel_addr);
    reg_val &= ~(0x03 << (((port_num - (port_num_dlevel<<4))<<1)));
    reg_val |=  (set_driver_level << (((port_num - (port_num_dlevel<<4))<<1)));
    GPIO_REG_WRITE(tmp_group_dlevel_addr, reg_val);

    return EGPIO_SUCCESS;
}

__s32  gpio_read_one_pin_value(ulong p_handler, const char *gpio_name)
{
    char               *tmp_buf;                                      
    __u32               group_count_max;                               
    system_gpio_set_t  *user_gpio_set = NULL, *tmp_sys_gpio_data;
    __u32               port, port_num, port_num_func, func_val;
    __u32                i, reg_val;
   
    if(!p_handler)
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    tmp_sys_gpio_data = (system_gpio_set_t *)(tmp_buf + 16);

    if(group_count_max == 0)
    {
        return EGPIO_FAIL;
    }
    else if(group_count_max == 1)
    {
        user_gpio_set = tmp_sys_gpio_data;
    }
    else if(gpio_name)
    {
        for(i=0; i<group_count_max; i++)
        {
            if(strcmp(gpio_name, tmp_sys_gpio_data->gpio_name))
            {
                tmp_sys_gpio_data ++;
                continue;
            }
            user_gpio_set = tmp_sys_gpio_data;
            break;
        }
    }
    if(!user_gpio_set)
    {
        return EGPIO_FAIL;
    }

    port     = user_gpio_set->port;
    port_num = user_gpio_set->port_num;
    port_num_func = port_num >> 3;

    reg_val  = PIO_REG_CFG_VALUE(port, port_num_func);

    func_val = (reg_val >> ((port_num - (port_num_func<<3))<<2)) & PIO_CFG_MASK;
    if(func_val == 0)
    {
        reg_val = (PIO_REG_DATA_VALUE(port) >> port_num) & 0x01;
        return reg_val;
    }

    return EGPIO_FAIL;
}

__s32  gpio_write_one_pin_value(ulong p_handler, __u32 value_to_gpio, const char *gpio_name)
{
    char               *tmp_buf;                                       
    __u32               group_count_max;                             
    system_gpio_set_t  *user_gpio_set = NULL, *tmp_sys_gpio_data;
    volatile __u32     *tmp_group_data_addr = NULL;
    __u32               port, port_num, port_num_func, func_val;
    __u32                i, reg_val;
   
    if(!p_handler)
    {
        return EGPIO_FAIL;
    }
    if(value_to_gpio >= 2)
    {
        return EGPIO_FAIL;
    }
    tmp_buf = (char *)p_handler;
    group_count_max = *(int *)tmp_buf;
    tmp_sys_gpio_data = (system_gpio_set_t *)(tmp_buf + 16);

    if(group_count_max == 0)
    {
        return EGPIO_FAIL;
    }
    else if(group_count_max == 1)
    {
        user_gpio_set = tmp_sys_gpio_data;
    }
    else if(gpio_name)
    {
        for(i=0; i<group_count_max; i++)
        {
            if(strcmp(gpio_name, tmp_sys_gpio_data->gpio_name))
            {
                tmp_sys_gpio_data ++;
                continue;
            }
            user_gpio_set = tmp_sys_gpio_data;
            break;
        }
    }
    if(!user_gpio_set)
    {
        return EGPIO_FAIL;
    }

    port     = user_gpio_set->port;
    port_num = user_gpio_set->port_num;
    port_num_func = port_num >> 3;

    reg_val  = PIO_REG_CFG_VALUE(port, port_num_func);
    func_val = (reg_val >> ((port_num - (port_num_func<<3))<<2)) & PIO_CFG_MASK;
    if(func_val == 1)
    {
        tmp_group_data_addr = PIO_REG_DATA(port);
        reg_val = GPIO_REG_READ(tmp_group_data_addr);
        reg_val &= ~(1 << port_num);
        reg_val |=  (value_to_gpio << port_num);
        GPIO_REG_WRITE(tmp_group_data_addr, reg_val);

        return EGPIO_SUCCESS;
    }

    return EGPIO_FAIL;
}

int gpio_request_early(void  *user_gpio_list, __u32 group_count_max, __s32 set_gpio)
{
	user_gpio_set_t    *tmp_user_gpio_data, *gpio_list;
	__u32				first_port;                      
	__u32               tmp_group_func_data;
	__u32               tmp_group_pull_data;
	__u32               tmp_group_dlevel_data;
	__u32               tmp_group_data_data;
	__u32               data_change = 0;
	//	__u32			   *tmp_group_port_addr;
	volatile __u32     *tmp_group_func_addr,   *tmp_group_pull_addr;
	volatile __u32     *tmp_group_dlevel_addr, *tmp_group_data_addr;
	__u32  				port, port_num, port_num_func, port_num_pull, port_num_dlevel;
	__u32  				pre_port, pre_port_num_func;
	__u32  				pre_port_num_pull;
	__s32               i, tmp_val;


	debug("gpio: conut=%d, set gpio = %d\n", group_count_max, set_gpio);
		gpio_list = (user_gpio_set_t *)user_gpio_list;

	for(first_port = 0; first_port < group_count_max; first_port++)
	{
		tmp_user_gpio_data = gpio_list + first_port;
		port     = tmp_user_gpio_data->port;                        
		port_num = tmp_user_gpio_data->port_num;                  
		if(!port)
		{
			continue;
		}
		port_num_func = (port_num >> 3);
		port_num_pull = (port_num >> 4);
		port_num_dlevel = (port_num / PIOC_o_DLEVEL);

		tmp_group_func_addr    = PIO_REG_CFG(port, port_num_func);  
		tmp_group_pull_addr    = PIO_REG_PULL(port, port_num_pull); 
		tmp_group_dlevel_addr  = PIO_REG_DLEVEL(port, port_num_dlevel);
		tmp_group_data_addr    = PIO_REG_DATA(port);

		tmp_group_func_data    = GPIO_REG_READ(tmp_group_func_addr);
		tmp_group_pull_data    = GPIO_REG_READ(tmp_group_pull_addr);
		tmp_group_dlevel_data  = GPIO_REG_READ(tmp_group_dlevel_addr);
		tmp_group_data_data    = GPIO_REG_READ(tmp_group_data_addr);

		pre_port          = port;
		pre_port_num_func = port_num_func;
		pre_port_num_pull = port_num_pull;

		tmp_val = (port_num - (port_num_func << 3)) << 2;
		tmp_group_func_data &= ~(PIO_CFG_MASK << tmp_val);
		if(set_gpio)
		{
			tmp_group_func_data |= (tmp_user_gpio_data->mul_sel & PIO_CFG_MASK) << tmp_val;
		}

		tmp_val = (port_num - (port_num_pull << 4)) << 1;
		if(tmp_user_gpio_data->pull >= 0)
		{
			tmp_group_pull_data &= ~(                           0x03  << tmp_val);
			tmp_group_pull_data |=  (tmp_user_gpio_data->pull & 0x03) << tmp_val;
		}
#if (PIOC_o_DLEVEL == 8)
		tmp_val = (port_num % 8) * 4;
#endif
		if(tmp_user_gpio_data->drv_level >= 0)
		{
			tmp_group_dlevel_data &= ~(                                0x03  << tmp_val);
			tmp_group_dlevel_data |=  (tmp_user_gpio_data->drv_level & 0x03) << tmp_val;
		}

		if(tmp_user_gpio_data->mul_sel == 1)
		{
		    if(tmp_user_gpio_data->data >= 0)
		    {
		    	tmp_val = tmp_user_gpio_data->data & 1;
		        tmp_group_data_data &= ~(1 << port_num);
		        tmp_group_data_data |= tmp_val << port_num;
		        data_change = 1;
		    }
		}
		debug("---name = %s, port = %d,portnum=%d,mul_sel=%d,pull=%d drive= %d, data=%d\n",
					tmp_user_gpio_data->gpio_name,
					tmp_user_gpio_data->port,
					tmp_user_gpio_data->port_num,
					tmp_user_gpio_data->mul_sel,
					tmp_user_gpio_data->pull,
					tmp_user_gpio_data->drv_level,
					tmp_user_gpio_data->data);
	

		break;
	}

	if(first_port >= group_count_max)
	{
	    return -1;
	}

	for(i = first_port + 1; i < group_count_max; i++)
	{
		tmp_user_gpio_data = gpio_list + i;
		port     = tmp_user_gpio_data->port;
		port_num = tmp_user_gpio_data->port_num;
		debug("+++name = %s, port = %d,portnum=%d,mul_sel=%d,pull=%d drive= %d, data=%d\n",
				tmp_user_gpio_data->gpio_name,
				tmp_user_gpio_data->port,
				tmp_user_gpio_data->port_num,
				tmp_user_gpio_data->mul_sel,
				tmp_user_gpio_data->pull,
				tmp_user_gpio_data->drv_level,
				tmp_user_gpio_data->data);
		if(!port)
		{
			break;
		}
		port_num_func = (port_num >> 3);
		port_num_pull = (port_num >> 4);
		port_num_dlevel = (port_num / PIOC_o_DLEVEL);

		if ((port_num_pull != pre_port_num_pull) || (port != pre_port) || (pre_port_num_func != port_num_func)) {
			GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data);
			GPIO_REG_WRITE(tmp_group_pull_addr, tmp_group_pull_data); 
			GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data);
			if(data_change)
			{
				data_change = 0;
				GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data);
			}

			tmp_group_func_addr    = PIO_REG_CFG(port, port_num_func); 
			tmp_group_pull_addr    = PIO_REG_PULL(port, port_num_pull);
			tmp_group_dlevel_addr  = PIO_REG_DLEVEL(port, port_num_dlevel);
			tmp_group_data_addr    = PIO_REG_DATA(port);  


			tmp_group_func_data    = GPIO_REG_READ(tmp_group_func_addr);
			tmp_group_pull_data    = GPIO_REG_READ(tmp_group_pull_addr);
			tmp_group_dlevel_data  = GPIO_REG_READ(tmp_group_dlevel_addr);
			tmp_group_data_data    = GPIO_REG_READ(tmp_group_data_addr);
		}

		pre_port_num_pull = port_num_pull;                    
		pre_port_num_func = port_num_func;
		pre_port          = port;

	
		tmp_val = (port_num - (port_num_func << 3)) << 2;
		if(tmp_user_gpio_data->mul_sel >= 0)
		{
			tmp_group_func_data &= ~(PIO_CFG_MASK  << tmp_val);
			if(set_gpio)
			{
				tmp_group_func_data |=  (tmp_user_gpio_data->mul_sel & PIO_CFG_MASK) << tmp_val;
			}
		}

		tmp_val = (port_num - (port_num_pull << 4)) << 1;
		if(tmp_user_gpio_data->pull >= 0)
		{
			tmp_group_pull_data &= ~(                           0x03  << tmp_val);
			tmp_group_pull_data |=  (tmp_user_gpio_data->pull & 0x03) << tmp_val;
		}
#if (PIOC_o_DLEVEL == 8)
		tmp_val = (port_num % 8) * 4;
#endif
		if(tmp_user_gpio_data->drv_level >= 0)
		{
			tmp_group_dlevel_data &= ~(                                0x03  << tmp_val);
			tmp_group_dlevel_data |=  (tmp_user_gpio_data->drv_level & 0x03) << tmp_val;
		}
      
		if(tmp_user_gpio_data->mul_sel == 1)
		{
		    if(tmp_user_gpio_data->data >= 0)
		    {
		    	tmp_val = tmp_user_gpio_data->data & 1;
		        tmp_group_data_data &= ~(1 << port_num);
		        tmp_group_data_data |= tmp_val << port_num;
		        data_change = 1;
		    }
		}
      
	}
        
	if(tmp_group_func_addr)                        
	{                                              
		GPIO_REG_WRITE(tmp_group_func_addr,   tmp_group_func_data); 
		GPIO_REG_WRITE(tmp_group_pull_addr,   tmp_group_pull_data); 
		GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data);
		if(data_change)
		{
		    GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data);
		}
	}

    return 0;
}

ulong sunxi_gpio_request(user_gpio_set_t *gpio_list, __u32 group_count_max)
{
    char               *user_gpio_buf;                                     
    system_gpio_set_t  *user_gpio_set, *tmp_sys_gpio_data;
    user_gpio_set_t  *tmp_user_gpio_data;
    __u32                real_gpio_count = 0, first_port;
    __u32               tmp_group_func_data = 0;
    __u32               tmp_group_pull_data = 0;
    __u32               tmp_group_dlevel_data = 0;
    __u32               tmp_group_data_data = 0;
    __u32               func_change = 0, pull_change = 0;
    __u32               dlevel_change = 0, data_change = 0;
    volatile __u32  *tmp_group_func_addr = NULL, *tmp_group_pull_addr = NULL;
    volatile __u32  *tmp_group_dlevel_addr = NULL, *tmp_group_data_addr = NULL;
    __u32  port, port_num, port_num_func, port_num_pull, port_num_dlevel;
    __u32  pre_port = 0x7fffffff, pre_port_num_func = 0x7fffffff;
    __u32  pre_port_num_pull = 0x7fffffff;
    __s32  i, tmp_val;
    if((!gpio_list) || (!group_count_max))
    {
        return (u32)0;
    }
    for(i = 0; i < group_count_max; i++)
    {
        tmp_user_gpio_data = gpio_list + i;        
        if(!tmp_user_gpio_data->port)
        {
            continue;
        }
        real_gpio_count ++;
    }

 
    user_gpio_buf = (char *)malloc(16 + sizeof(system_gpio_set_t) * real_gpio_count);  
    if(!user_gpio_buf)
    {
        return (u32)0;
    }
    memset(user_gpio_buf, 0, 16 + sizeof(system_gpio_set_t) * real_gpio_count);        
    *(int *)user_gpio_buf = real_gpio_count;                                          
    user_gpio_set = (system_gpio_set_t *)(user_gpio_buf + 16);                    
   
    for(first_port = 0; first_port < group_count_max; first_port++)
    {
        tmp_user_gpio_data = gpio_list + first_port;
        port     = tmp_user_gpio_data->port;                       
        port_num = tmp_user_gpio_data->port_num;                    
        if(!port)
        {
            continue;
        }
        port_num_func = (port_num >> 3);
        port_num_pull = (port_num >> 4);
	port_num_dlevel = (port_num / PIOC_o_DLEVEL);


        tmp_group_func_addr    = PIO_REG_CFG(port, port_num_func); 
        tmp_group_pull_addr    = PIO_REG_PULL(port, port_num_pull);
	tmp_group_dlevel_addr  = PIO_REG_DLEVEL(port, port_num_dlevel);
        tmp_group_data_addr    = PIO_REG_DATA(port);               

        tmp_group_func_data    = *tmp_group_func_addr;
        tmp_group_pull_data    = *tmp_group_pull_addr;
        tmp_group_dlevel_data  = *tmp_group_dlevel_addr;
        tmp_group_data_data    = *tmp_group_data_addr;
        break;
    }
    if(first_port >= group_count_max)
    {
        return 0;
    }
   
    for(i = first_port; i < group_count_max; i++)
    {
        tmp_sys_gpio_data  = user_gpio_set + i;            
        tmp_user_gpio_data = gpio_list + i;                
        port     = tmp_user_gpio_data->port;             
        port_num = tmp_user_gpio_data->port_num;
        if(!port)
        {
            continue;
        }
      
        strcpy(tmp_sys_gpio_data->gpio_name, tmp_user_gpio_data->gpio_name);
        tmp_sys_gpio_data->port                       = port;
        tmp_sys_gpio_data->port_num                   = port_num;
        tmp_sys_gpio_data->user_gpio_status.mul_sel   = tmp_user_gpio_data->mul_sel;
        tmp_sys_gpio_data->user_gpio_status.pull      = tmp_user_gpio_data->pull;
        tmp_sys_gpio_data->user_gpio_status.drv_level = tmp_user_gpio_data->drv_level;
        tmp_sys_gpio_data->user_gpio_status.data      = tmp_user_gpio_data->data;

        port_num_func = (port_num >> 3);
        port_num_pull = (port_num >> 4);
	port_num_dlevel = (port_num / 8);

	if ((port_num_pull != pre_port_num_pull) || (port != pre_port) || (pre_port_num_func != port_num_func)) {
            if(func_change)
            {
                *tmp_group_func_addr   = tmp_group_func_data;  
                func_change = 0;
            }
            if(pull_change)
            {
                pull_change = 0;
                *tmp_group_pull_addr   = tmp_group_pull_data;  
            }
            if(dlevel_change)
            {
                dlevel_change = 0;
                *tmp_group_dlevel_addr = tmp_group_dlevel_data;
            }
            if(data_change)
            {
                data_change = 0;
                *tmp_group_data_addr   = tmp_group_data_data;
            }

            tmp_group_func_addr    = PIO_REG_CFG(port, port_num_func); 
            tmp_group_pull_addr    = PIO_REG_PULL(port, port_num_pull);
            tmp_group_dlevel_addr  = PIO_REG_DLEVEL(port, port_num_pull);
            tmp_group_data_addr    = PIO_REG_DATA(port); 

			tmp_group_func_data    = *tmp_group_func_addr;
            tmp_group_pull_data    = *tmp_group_pull_addr;
            tmp_group_dlevel_data  = *tmp_group_dlevel_addr;
            tmp_group_data_data    = *tmp_group_data_addr;

        }
        pre_port_num_pull = port_num_pull;   
        pre_port_num_func = port_num_func;
        pre_port          = port;

    
        if(tmp_user_gpio_data->mul_sel >= 0)
        {
            tmp_val = (port_num - (port_num_func<<3)) << 2;
            tmp_sys_gpio_data->hardware_gpio_status.mul_sel = (tmp_group_func_data >> tmp_val) & PIO_CFG_MASK;
            tmp_group_func_data &= ~(                              PIO_CFG_MASK  << tmp_val);
            tmp_group_func_data |=  (tmp_user_gpio_data->mul_sel & PIO_CFG_MASK) << tmp_val;
            func_change = 1;
        }
     

        tmp_val = (port_num - (port_num_pull<<4)) << 1;

        if(tmp_user_gpio_data->pull >= 0)
        {
            tmp_sys_gpio_data->hardware_gpio_status.pull = (tmp_group_pull_data >> tmp_val) & 0x03;
            if(tmp_user_gpio_data->pull >= 0)
            {
                tmp_group_pull_data &= ~(                           0x03  << tmp_val);
                tmp_group_pull_data |=  (tmp_user_gpio_data->pull & 0x03) << tmp_val;
                pull_change = 1;
            }
        }
#if (PIOC_o_DLEVEL == 8)
	tmp_val = (port_num % 8) * 4;
#endif
        if(tmp_user_gpio_data->drv_level >= 0)
        {
            tmp_sys_gpio_data->hardware_gpio_status.drv_level = (tmp_group_dlevel_data >> tmp_val) & 0x03;
            if(tmp_user_gpio_data->drv_level >= 0)
            {
                tmp_group_dlevel_data &= ~(                                0x03  << tmp_val);
                tmp_group_dlevel_data |=  (tmp_user_gpio_data->drv_level & 0x03) << tmp_val;
                dlevel_change = 1;
            }
        }
      
        if(tmp_user_gpio_data->mul_sel == 1)
        {
            if(tmp_user_gpio_data->data >= 0)
            {
                tmp_val = tmp_user_gpio_data->data;
                tmp_val &= 1;
                tmp_group_data_data &= ~(1 << port_num);
                tmp_group_data_data |= tmp_val << port_num;
                data_change = 1;
            }
        }
    }

   
    if(tmp_group_func_addr)                        
    {                                              
        *tmp_group_func_addr   = tmp_group_func_data;     
        if(pull_change)
        {
            *tmp_group_pull_addr   = tmp_group_pull_data;  
        }
        if(dlevel_change)
        {
            *tmp_group_dlevel_addr = tmp_group_dlevel_data;
        }
        if(data_change)
        {
            *tmp_group_data_addr   = tmp_group_data_data;   
        }
    }
    return (ulong)user_gpio_buf;
}

       
//note : just free malloc memory
__s32 gpio_release(ulong p_handler, __s32 unused_para)
{
	char               *tmp_buf;                                     
	__u32               group_count_max;             

	if(!p_handler)
	{
		return EGPIO_FAIL;
	}
	tmp_buf = (char *)p_handler;
	group_count_max = *(int *)tmp_buf;
	if(!group_count_max)
	{
		return EGPIO_FAIL;
	}

	free((char *)p_handler);

	return EGPIO_SUCCESS;
}




#define FDT_INFO(fmt,args...) printf("FDT INFO:"fmt,##args);
#define FDT_ERR(fmt,args...) printf("FDT ERROR:"fmt,##args);

static int fdt_get_new_pull(int nodeoffset)
{
	if (fdt_getprop_string(working_fdt, nodeoffset,
			"bias-pull-up", NULL) >= 0)
		return 1;
	if (fdt_getprop_string(working_fdt, nodeoffset,
			"bias-pull-down", NULL) >= 0)
		return 0;
	if (fdt_getprop_string(working_fdt, nodeoffset,
			"bias-disable", NULL) >= 0)
		return 0;

	return -1;
}

/**
 * fdt_get_pin - Read all pin from node
 *
 * @node_path: fdt path or alians
 * @prop_name:  pin property name--ex "pinctrl-0"
 * @gpio_list:  recevice the gpio data
 */
int fdt_get_all_pin(int nodeoffset,const char* pinctrl_name,user_gpio_set_t* gpio_list)
{
	//int  nodeoffset;	/* node offset from libfdt */
	char *pins = NULL;
	char *function = NULL;
	int  ret;
	char path_tmp[128] = {0};
	char port_name[32][12]; //format PA0,PB6 ....
	char pin_name[32][64] = {{0}}; //
	u32 handle[10] = {0};
	int handle_num = 0;
	int i,j;
	int name_num = 0,port_num = 0;
	int gpio_list_index = 0;

	u32 pull;
	u32 drive;
	u32 muxsel;

	//get property vaule by handle
	/*nodeoffset = fdt_path_offset (working_fdt,node_path );
	if(nodeoffset < 0)
	{
		printf ("error:fdt err returned %s\n",fdt_strerror(nodeoffset));
		return -1;
	}*/
	handle_num = fdt_getprop_u32(working_fdt,nodeoffset,pinctrl_name,handle);
	if(handle_num < 0)
	{
		FDT_ERR("%s:get property handle %s error:%s\n",__func__, pinctrl_name,fdt_strerror(handle_num) );
		return -1;
	}
	for(i = 0; i < handle_num; i++)
	{
		debug("%s:get property handle  %s ok, index %d,value is 0x%x\n",__func__, pinctrl_name,i,handle[i] );
		nodeoffset = fdt_node_offset_by_phandle(working_fdt,handle[i]);
		if(nodeoffset < 0 )
		{
			FDT_ERR("%s:get property by handle error\n",__func__);
			return -1;
		}
		ret = fdt_get_path(working_fdt,nodeoffset,path_tmp,sizeof(path_tmp));
		if(ret < 0 )
		{
			FDT_ERR("%s:get path by nodeoffset error\n",__func__);
			return -1;
		}
		debug("path for handle is %s\n", path_tmp);

		name_num = 0;
		port_num = 0;
		ret = fdt_getprop_string(working_fdt,nodeoffset,"allwinner,pins",&pins);
		if (ret < 0)
			ret = fdt_getprop_string(working_fdt, nodeoffset,
								"pins", &pins);
		if(ret >=0 )
		{
			int len = ret;
			char *data = pins;
			j = 0;
			while (j < len) {
				strcpy(port_name[port_num++],data);
				j    += strlen(data) + 1;
				data += strlen(data) + 1;
			}
		}

		ret = fdt_getprop_string(working_fdt,nodeoffset,"allwinner,pname",&pins);
		if (ret < 0)
			ret = fdt_getprop_string(working_fdt, nodeoffset,
							"pname", &pins);

		if(ret >=0 )
		{
			int len = ret;
			char *data = pins;
			j = 0;
			while (j < len) {
				strcpy(pin_name[name_num++],data);
				j    += strlen(data) + 1;
				data += strlen(data) + 1;
			}
		}
#if 0
		if(name_num != port_num)
		{
			printf ("error:pin name num(%d) != port num(%d)\n",name_num, port_num);
			return -1;
		}
#endif
		ret = fdt_getprop_string(working_fdt,nodeoffset,"allwinner,function",&function);
		if (ret < 0)
		{
			ret = fdt_getprop_string(working_fdt, nodeoffset,
						"function", &function);
			if (ret < 0) {
				FDT_ERR("get function err returned %s\n",
							fdt_strerror(ret));
				return -1;
			}
		}

		ret = fdt_getprop_u32(working_fdt,nodeoffset,"allwinner,muxsel",&muxsel);
		if (ret < 0)
		{
			ret = fdt_getprop_u32(working_fdt, nodeoffset,
						"muxsel", &muxsel);
			if (ret < 0) {
				FDT_ERR("get muxsel err returned %s\n",
							fdt_strerror(ret));
				return -1;
			}
		}

		ret = fdt_getprop_u32(working_fdt,nodeoffset,"allwinner,drive",&drive);
		if (ret < 0)
		{
			ret = fdt_getprop_u32(working_fdt, nodeoffset,
						"drive-strength", &drive);
			if (ret < 0) {
				FDT_ERR("get drive err returned %s\n",
							fdt_strerror(ret));
				return -1;
			}
			switch (drive) {
			case 10:
				drive = 0;
				break;
			case 20:
				drive = 1;
				break;
			case 30:
				drive = 2;
				break;
			case 40:
				drive = 3;
				break;
			default:
				FDT_ERR("get drive value err %d\n", drive);
				return -1;
			}

		}

		ret = fdt_getprop_u32(working_fdt,nodeoffset,"allwinner,pull",&pull);
		if(ret < 0)
		{
			pull = fdt_get_new_pull(nodeoffset);
			if (pull < 0) {
				FDT_ERR("get pull err returned %s\n",
							fdt_strerror(ret));
				return -1;
			}
		}
		for(j = 0; j < port_num; j++)
		{
			char *src;
			char ch;
			int tmp_value = 0;
			int tmp_mul;

			src = &port_name[j][2];
			ch = *src++;
			while(ch != '\0')
			{
				if((ch >= '0') && (ch <= '9'))
				{
					tmp_value = tmp_value * 10 + (ch - '0');
					ch = *src++;
				}
				else
				{
					FDT_ERR("format gpio %s\n",pin_name[j] );
					break;
				}
			}
			tmp_mul = muxsel;//get_mul_by_func_name(function);
			if(tmp_mul<0)
			{
				FDT_ERR(" muxsel not configed\n");
				return -1;
			}
			strcpy(gpio_list[gpio_list_index].gpio_name, pin_name[j]);
			gpio_list[gpio_list_index].port = port_name[j][1] - 'A'+1;
			gpio_list[gpio_list_index].port_num = tmp_value;
			gpio_list[gpio_list_index].mul_sel = tmp_mul & 0xf;
			gpio_list[gpio_list_index].pull = pull;
			gpio_list[gpio_list_index].drv_level = drive;
			gpio_list[gpio_list_index].data = 0;
			gpio_list_index++;
		}
	}

	for(i = 0; i < gpio_list_index; i++)
	{
		debug("name = %s, port = %d,portnum=%d,mul_sel=%d,pull=%d drive= %d, data=%d\n",
			gpio_list[i].gpio_name,
			gpio_list[i].port,
			gpio_list[i].port_num,
			gpio_list[i].mul_sel,
			gpio_list[i].pull,
			gpio_list[i].drv_level,
			gpio_list[i].data);

	}
	return gpio_list_index;
}

/**
 * fdt_get_pin_num - get pin num from  device node
 *
 * @node_path: device path or alians
 * @prop_name: ex "pinctrl-0"

 */
int fdt_get_pin_num(int nodeoffset,const char* pinctrl_name)
{
	//int  nodeoffset;	/* node offset from libfdt */
	char *pins = NULL;
	int  ret;
	u32 handle[10] = {0};
	int handle_num = 0;
	int i,j;
	int port_num = 0;

	//get property vaule by handle
	/*nodeoffset = fdt_path_offset (working_fdt,node_path );
	if(nodeoffset < 0)
	{
		printf ("error:fdt err returned %s\n",fdt_strerror(nodeoffset));
		return -1;
	}*/
	handle_num = fdt_getprop_u32(working_fdt,nodeoffset,pinctrl_name,handle);
	if(handle_num < 0)
	{
		FDT_ERR("%s:get property handle %s error:%s\n",__func__, pinctrl_name,fdt_strerror(handle_num) );
		return -1;
	}
	port_num = 0;
	for(i = 0; i < handle_num; i++)
	{
		//printf("get property handle  %s ok, index %d,value is 0x%x\n", "pinctrl-0",i,handle[i] );
		nodeoffset = fdt_node_offset_by_phandle(working_fdt,handle[i]);
		if(nodeoffset < 0 )
		{
			FDT_ERR("%s:get property by handle error\n",__func__);
			return -1;
		}
		ret = fdt_getprop_string(working_fdt,nodeoffset,"allwinner,pins",&pins);
		if (ret < 0)
			ret = fdt_getprop_string(working_fdt, nodeoffset,
								"pins", &pins);
		if(ret >=0 )
		{
			int len = ret;
			char *data = pins;
			j = 0;
			while (j < len) {
				port_num++;
				j    += strlen(data) + 1;
				data += strlen(data) + 1;
			}
		}
	}
	return port_num;
}


/**
 * fdt_config_all_pin - config all pin for device
 *
 * @node_path:  device tree path

 */
int fdt_set_all_pin(const char* node_path,const char* pinctrl_name)
{
	user_gpio_set_t  pin_set[32];
	int pin_count = 0;
	int ret = 0;
	int nodeoffset;

	//get property vaule by handle
	nodeoffset = fdt_path_offset (working_fdt,node_path );
	if(nodeoffset < 0)
	{
		FDT_ERR("%s:[%s]-->%s\n",__func__,node_path,fdt_strerror(nodeoffset));
		return -1;
	}
#if 0
	pin_count = fdt_get_pin_num(nodeoffset,pinctrl_name);
	if(pin_count < 0)
	{
		return -1;
	}
	pin_set = malloc(pin_count*sizeof(user_gpio_set_t));
	if(pin_set == NULL)
	{
		FDT_ERR("%s:malloc fail\n", __func__);
		return -1;
	}
#endif
	pin_count = fdt_get_all_pin( nodeoffset, pinctrl_name,pin_set);
	if(pin_count < 0)
	{
		return -1;
	}
	ret =  gpio_request_early(pin_set,pin_count,1);
	//free(pin_set);

	return ret;
}

int fdt_set_all_pin_by_offset(int nodeoffset,const char* pinctrl_name)
{
	user_gpio_set_t  pin_set[32] ;
	int pin_count = 0;
	int ret = 0;

	if(nodeoffset < 0)
	{
		FDT_ERR("%s:fdt bad nodeoffset %d\n",__func__,nodeoffset);
		return -1;
	}
	memset(pin_set, 0 , sizeof(pin_set));
	#if 0
	pin_count = fdt_get_pin_num(nodeoffset,pinctrl_name);
	if(pin_count < 0)
	{
		return -1;
	}

	pin_set = malloc(pin_count*sizeof(user_gpio_set_t));
	if(pin_set == NULL)
	{
		FDT_ERR("%s:malloc fail\n", __func__);
		return -1;
	}
	#endif
	pin_count = fdt_get_all_pin( nodeoffset, pinctrl_name,pin_set);
	if(pin_count < 0)
	{
		return -1;
	}
	ret =  gpio_request_early(pin_set,pin_count,1);
	//free(pin_set);

	return ret;
}

/**
 * fdt_config_all_pin - config all pin for device
 *
 * @node_path:  device tree path

 */
int fdt_set_pin_byname(user_gpio_set_t  *pin_list,int pin_count, const char* pin_name)
{
	user_gpio_set_t  *pin;
	int ret = 0;
	int i = 0;
	for(i = 0; i < pin_count; i++)
	{
		pin = pin_list+i;
		if(strcmp(pin->gpio_name, pin_name) == 0)
		{
			break;
		}
	}
	//not find
	if(i >= pin_count)
	{
		return -1;
	}

	ret =  gpio_request_early(pin,1,1);

	return ret;
}


/**
 * fdt_get_gpio - Read one gpio from node
 *
 * @nodeoffset: fdt nodeoffset
 * @prop_name:  gpio property naem
 * @gpio_list:  recevice the gpio data
 */
int fdt_get_one_gpio_by_offset(int nodeoffset, const char* prop_name,user_gpio_set_t* gpio_list)
{
	int ret ;
	u32 data[10];

	memset(data, 0, sizeof(data));
	//get property vaule by handle
	if(nodeoffset < 0)
	{
		debug ("fdt err returned %s\n",fdt_strerror(nodeoffset));
		return -1;
	}

	ret = fdt_getprop_u32(working_fdt,nodeoffset,prop_name,data);
	if(ret < 0 )
	{
		debug("%s : err returned %s\n",__func__,fdt_strerror(ret));
		return -1;
	}

	strcpy(gpio_list->gpio_name,prop_name);

	gpio_list->port = data[1] + 1;  //0: PA
	gpio_list->port_num = data[2];
	gpio_list->mul_sel = data[3];
	gpio_list->pull = data[4];
	gpio_list->drv_level = data[5];
	gpio_list->data = data[6];

	debug("name = %s, port = %x,portnum=%x,mul_sel=%x,pull=%x drive= %x, data=%x\n",
			gpio_list->gpio_name,
			gpio_list->port,
			gpio_list->port_num,
			gpio_list->mul_sel,
			gpio_list->pull,
			gpio_list->drv_level,
			gpio_list->data);
	return ret;

}

int fdt_get_one_gpio(const char* node_path, const char* prop_name,user_gpio_set_t* gpio_list)
{
	int nodeoffset;	/* node offset from libfdt */
	int ret ;
	u32 data[10];

	memset(data, 0, sizeof(data));
	//get property vaule by handle
	nodeoffset = fdt_path_offset (working_fdt,node_path );
	if(nodeoffset < 0)
	{
		debug ("fdt err returned %s\n",fdt_strerror(nodeoffset));
		return -1;
	}

	ret = fdt_getprop_u32(working_fdt,nodeoffset,prop_name,data);
	if(ret < 0 )
	{
		debug("%s :%s|%s err returned %s\n",__func__,node_path,prop_name,fdt_strerror(ret));
		return -1;
	}

	strcpy(gpio_list->gpio_name,prop_name);

	gpio_list->port = data[1] + 1;  //0: PA
	gpio_list->port_num = data[2];
	gpio_list->mul_sel = data[3];
	gpio_list->pull = data[4];
	gpio_list->drv_level = data[5];
	gpio_list->data = data[6];

	debug("name = %s, port = %x,portnum=%x,mul_sel=%x,pull=%x drive= %x, data=%x\n",
			gpio_list->gpio_name,
			gpio_list->port,
			gpio_list->port_num,
			gpio_list->mul_sel,
			gpio_list->pull,
			gpio_list->drv_level,
			gpio_list->data);
	return 0;

}
/**
 * fdt_set_one_gpio - config one gpio for device
 *
 * @node_path:  device tree path
 * @prop_name: gpio name  ex "vdevice_gpio_1"   ---- vdevice_gpio_1 = <&r_pio PL 0 1 1 1 1>;
 */
int fdt_set_one_gpio(const char* node_path, const char* prop_name)
{
	user_gpio_set_t gpio_set[1];
	if(fdt_get_one_gpio(node_path, prop_name,gpio_set))
	{
		return -1;
	}
	return gpio_request_early(&gpio_set,1,1);
}


int fdt_set_normal_gpio(user_gpio_set_t  *gpio_set, int gpio_count)
{
	return gpio_request_early(&gpio_set,gpio_count,1);
}

int script_parser_fetch(char *node_path, char *prop_name, int value[], int def_val)
{
	int nodeoffset; 
	int ret;

	//get property vaule by handle
	nodeoffset = fdt_path_offset (working_fdt, node_path );
	if(nodeoffset < 0) {
		debug ("fdt err returned %s\n",fdt_strerror(nodeoffset));
		value[0] = def_val;
		return -1;
	}

	ret = fdt_getprop_u32(working_fdt,nodeoffset, prop_name, (u32*)value);
	if(ret < 0 ) {
		debug("%s :%s|%s err returned %s\n",__func__,node_path,prop_name,fdt_strerror(ret));
		value[0] = def_val;
		return -1;
	}

	return 0;
}

/**
 * fdt_get_regulator_name - get regulator name from device node
 *
 * @node_path: device path or alians
 * @prop_name: ex "pinctrl-0"

 */
const char *fdt_get_regulator_name(int nodeoffset, const char *name)
{
	char supply_name[32];
	u32 handle = 0;
	int handle_num = 0;

	sprintf(supply_name, "%s-supply", name);

	handle_num = fdt_getprop_u32(working_fdt, nodeoffset, supply_name, &handle);
	if (handle_num < 0) {
		FDT_ERR("%s:get property handle %s error:%s\n",
			__func__, supply_name, fdt_strerror(handle_num));
		return NULL;
	}

	nodeoffset = fdt_node_offset_by_phandle(working_fdt, handle);
	if (nodeoffset < 0) {
		FDT_ERR("%s:get property by handle error\n", __func__);
		return NULL;
	}

	return fdt_get_name(working_fdt, nodeoffset, NULL);
}

