SmartAudio/lichee/brandy/u-boot-2011.09/drivers/gpio/sunxi_gpio.c

187 lines
4.9 KiB
C
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* (C) Copyright 2007-2011
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang@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 <asm/io.h>
#include <asm/arch/gpio.h>
/*
************************************************************************************************************
*
* sunxi_set_gpio_all
*
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƣ<EFBFBD>
*
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD>
*
*
*
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ <EFBFBD><EFBFBD>
*
* ˵<EFBFBD><EFBFBD> <EFBFBD><EFBFBD>
*
*
************************************************************************************************************
*/
int sunxi_set_gpio_all(void *user_gpio_list, u32 group_count_max)
{
normal_gpio_cfg *user_gpio_data;
struct sunxi_gpio *gpio_group;
int port_first, port_last;
int port_num_first, port_num_last;
int actual_port;
uint port_func_cfg, port_pull_cfg, port_drv_cfg;
int port_num_other,port_num_func, last_port_num_other;
int other_cfg_ready, this_max_port_num;
int pull_changed, drv_changed;
int tmp_cfg_offset, tmp_other_offset;
int i, j;
//judge the count of valid gpio
user_gpio_data = (normal_gpio_cfg *)user_gpio_list;
for(i=0;i<group_count_max;i++)
{
if(!user_gpio_data->port)
{
break;
}
user_gpio_data ++;
actual_port ++;
}
actual_port = i;
if(actual_port <= 0)
{
return -1;
}
user_gpio_data = (normal_gpio_cfg *)user_gpio_list;
port_first = user_gpio_data->port;
port_num_first = user_gpio_data->port_num;
user_gpio_data += actual_port - 1;
port_last = user_gpio_data->port;
port_num_last = user_gpio_data->port_num;
if(port_first != port_last)
{
return -1;
}
gpio_group = (struct sunxi_gpio *)(SUNXI_PIO_BASE + sizeof(struct sunxi_gpio) * (port_first - 1));
other_cfg_ready = -1;
last_port_num_other = -1;
pull_changed = 0;
drv_changed = 0;
user_gpio_data = (normal_gpio_cfg *)user_gpio_list;
for(i = port_num_first; i < port_num_last;)
{
port_num_func = (i >> 3);
port_num_other = (i >> 4);
if(last_port_num_other != port_num_other)
{
last_port_num_other = port_num_other;
if(other_cfg_ready != -1)
{
if(pull_changed)
{
gpio_group->pull[port_num_other] = port_pull_cfg;
pull_changed = 0;
}
if(drv_changed)
{
gpio_group->drv[port_num_other] = port_drv_cfg;
drv_changed = 0;
}
}
other_cfg_ready = 0;
}
port_func_cfg = gpio_group->cfg[port_num_func];
if(!other_cfg_ready)
{
port_pull_cfg = gpio_group->pull[port_num_other];
port_drv_cfg = gpio_group->drv[port_num_other];
other_cfg_ready = 1;
}
this_max_port_num = (i & (~0x07)) + 7;
if(this_max_port_num > port_num_last)
{
this_max_port_num = port_num_last;
}
for(j= i; j <= this_max_port_num; j ++)
{
if(user_gpio_data->port_num != j)
{
continue; /* break this gpio */
}
tmp_cfg_offset = j - (port_num_func<<3);
tmp_other_offset = j - (port_num_other<<4);
port_func_cfg &= ~(0x07 << (tmp_cfg_offset * 4));
port_func_cfg |= user_gpio_data->mul_sel << (tmp_cfg_offset * 4);
if((user_gpio_data->pull >= 0) && (user_gpio_data->pull <= 2))
{
port_pull_cfg &= ~(0x03 << (tmp_other_offset * 2));
port_pull_cfg |= user_gpio_data->pull << (tmp_other_offset * 2);
pull_changed = 1;
}
if((user_gpio_data->drv_level>= 0) && (user_gpio_data->drv_level<= 2))
{
port_drv_cfg &= ~(0x03 << (tmp_other_offset * 2));
port_drv_cfg |= user_gpio_data->drv_level << (tmp_other_offset * 2);
drv_changed = 1;
}
user_gpio_data ++;
}
gpio_group->cfg[port_num_func] = port_func_cfg;
i = this_max_port_num;
}
if(other_cfg_ready != -1)
{
if(pull_changed)
{
gpio_group->pull[port_num_other] = port_pull_cfg;
pull_changed = 0;
}
if(drv_changed)
{
gpio_group->drv[port_num_other] = port_drv_cfg;
drv_changed = 0;
}
}
return 0;
}