cubieboard的uboot的GPIO的驱动详解
转发自我的博客:http://blog.sina.com.cn/s/blog_b5020b670101ft49.htmluboot的GPIO相当简单,其就是三层结构。分别为: 1、顶层接口层,其只定义了通用的接口,并不负责实现,实现是我们具体根据具体的芯片来实现的。
2、中间接口实现层,用具体的板子的GPIO来实现顶层的接口
3、 底层具体芯片GPIO的实现层 。
现在具体分析:
顶层接口层
int gpio_request(unsigned gpio, const char *label); //申请GPIO资源
int gpio_free(unsigned gpio); //释放申请的GPIO资源
int gpio_direction_input(unsigned gpio); //设置GPIO为输入模式
int gpio_direction_output(unsigned gpio, int value); //设置GPIO为输出模式
int gpio_get_value(unsigned gpio); //得到GPIO的值
int gpio_set_value(unsigned gpio, int value);//设置GPIO的值
说明:unsigned gpio为逻辑号,虽然和实际的物理GPIO地址有一定的关系,但并不是实际的物理GPIO地址。
中间接口实现层:
用具体的芯片的GPIO来实现其顶层接口
int gpio_request(unsigned gpio, const char *label)
{
return 0;
}
int gpio_free(unsigned gpio)
{
return 0;
}
int gpio_direction_input(unsigned gpio)
{
sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
return sunxi_gpio_input(gpio);
}
int gpio_direction_output(unsigned gpio, int value)
{
sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
return sunxi_gpio_output(gpio, value);
}
int gpio_get_value(unsigned gpio)
{
return sunxi_gpio_input(gpio);
}
int gpio_set_value(unsigned gpio, int value)
{
return sunxi_gpio_output(gpio, value);
}
底层具体芯片GPIO的实现层:
在实现的时候,其用了一个小技巧,其目的是把GPIO的物理寄存器放到结构体里面来,从而把物理的地址操作转换为数据结构的操作。
其实现如下:
把SUNXI_PIO_BASE 强制转换为sunxi_gpio_reg *指针来实现。
#define SUNXI_PIO_BASE 0x01c20800
struct sunxi_gpio {
u32 cfg;
u32 dat;
u32 drv;
u32 pull;
};
struct sunxi_gpio_int {
u32 cfg;
u32 ctl;
u32 sta;
u32 deb;
};
struct sunxi_gpio_reg {
struct sunxi_gpio gpio_bank;
u8 res;
struct sunxi_gpio_int gpio_int;
};
我们实现具体的芯片的GPIO的操作的思想是:
使用逻辑符号unsigned gpio,通过SUNXI_PIO_BASE 强制转换为sunxi_gpio_reg *指针的指针来操作相关寄存器。
但是逻辑符号unsigned gpio要通过SUNXI_PIO_BASE 强制转换为sunxi_gpio_reg *指针的指针来操作相关寄存器,必须要解决一个问题,即如何在众多的寄存器的中,找到指定的那个寄存器,并且在该寄存器上找到指定的那些相关位。
即gpio---->bank------>bank中的offset
这个映射关系和具体的芯片有关。
这里只讨论全志的a10芯片。
后面的写不了了,想看完整版的请看我的博客:http://blog.sina.com.cn/s/blog_b5020b670101ft49.html
LZ你好!我今天也在看全志A20 的gpio驱动。
【linux-3.4-cb2】
目录: driver/gpio/gpio-sunxi.c
------------------------
在这个驱动中,我看它使用的是platform平台设备相关编程。
-------------------------
由于是新手,其中有个疑点,还希望LZ能帮忙解答下。
--------------------------
首先,贴下代码:static int __init sunxi_gpio_init(void)
{
int err = 0;
err = platform_device_register(&sunxi_gpio_device);
if (err)
goto exit;
return platform_driver_register(&sunxi_gpio_driver);
exit:
return err;
}
subsys_initcall(sunxi_gpio_init);------------------------static int __devinit sunxi_gpio_probe(struct platform_device *pdev)
{
int i;
int err = 0;
int names_size = 0;
int gpio_used = 0;
int gpio_num = 0;
struct sunxi_gpio_data *gpio_i = NULL;
struct sunxi_gpio_data *gpio_data = NULL;
struct sunxi_gpio_chip *sunxi_chip = NULL;
char **pnames = NULL;
/* parse script.bin for section
gpio_used/gpio_num/gpio_pin_x */
pr_info("sunxi_gpio driver init ver %s\n", SUNXI_GPIO_VER);
err = script_parser_fetch("gpio_para", "gpio_used", &gpio_used,
sizeof(gpio_used)/sizeof(int));
if (err) {
/* Not error - just info */
pr_info("%s can't find script.bin '' 'gpio_used'\n",
__func__);
return err;
}
if (!gpio_used) {
pr_info("%s gpio_used is false. Skip gpio initialization\n",
__func__);
err = 0;
return err;
}
err = script_parser_fetch("gpio_para", "gpio_num", &gpio_num,
sizeof(gpio_num)/sizeof(int));
if (err) {
pr_err("%s script_parser_fetch '' 'gpio_num' err\n",
__func__);
return err;
}
if (!gpio_num) {
pr_info("%s gpio_num is none. Skip gpio initialization\n",
__func__);
err = 0;
return err;
}
/* Allocate memory for sunxi_gpio_chip + data/names array */
sunxi_chip = kzalloc(sizeof(struct sunxi_gpio_chip) +
sizeof(struct sunxi_gpio_data) * gpio_num,
GFP_KERNEL);
gpio_data = (void *)sunxi_chip + sizeof(struct sunxi_gpio_chip);
/* Allocate memory for variable array of fixed size strings */
/* in one chunk. This is to avoid 1+gpio_num kzalloc calls */
names_size = sizeof(*pnames) * gpio_num +
sizeof(char) * MAX_GPIO_NAMELEN * gpio_num;
pnames = kzalloc(names_size, GFP_KERNEL);
for (i = 0; i < gpio_num; i++) {
pnames = (void *)pnames + sizeof(*pnames) * gpio_num +
i * MAX_GPIO_NAMELEN;
}
if ((!pnames) || (!sunxi_chip)) {
pr_err("%s kzalloc failed\n", __func__);
err = -ENOMEM;
goto exit;
}
/* Parse gpio_para/pin script data */
gpio_i = gpio_data;
for (i = 0; i < gpio_num; i++) {
sprintf(gpio_i->pin_name, "gpio_pin_%d", i+1);
err = script_parser_fetch("gpio_para", gpio_i->pin_name,
(int *)&gpio_i->info,
sizeof(script_gpio_set_t));
if (err) {
pr_err("%s script_parser_fetch '' '%s' err\n",
__func__, gpio_i->pin_name);
break;
}
gpio_i++;
}
/* i/o的物理地址映射到核心虚拟地址空间内 */
sunxi_chip->gaddr = ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE);
if (!sunxi_chip->gaddr) {
pr_err("Can't request gpio registers memory\n");
err = -EIO;
goto unmap;
}
sunxi_chip->dev = &pdev->dev;
sunxi_chip->data = gpio_data;
sunxi_chip->chip = template_chip;
sunxi_chip->chip.ngpio = gpio_num;
sunxi_chip->chip.dev = &pdev->dev;
sunxi_chip->chip.label = "A1X_GPIO";
sunxi_chip->chip.base = 1;
sunxi_chip->chip.names = (const char *const *)pnames;
sunxi_chip->irq_base = -1;
/* configure EINTs for the detected SoC */
sunxi_gpio_eint_probe();
/* This needs additional system irq numbers (NR_IRQ=NR_IRQ+EINT_NUM) */
if (EINT_NUM > 0) {
sunxi_chip->irq_base = irq_alloc_descs(-1, 0, EINT_NUM, 0);
if (sunxi_chip->irq_base < 0) {
pr_err("Couldn't allocate virq numbers. GPIO irq support disabled\n");
err = sunxi_chip->irq_base;
}
} else
pr_info("GPIO irq support disabled in this platform\n");
/*自旋锁初始化*/
spin_lock_init(&sunxi_chip->irq_lock);
/*irq init*/
sunxi_gpio_irq_init(sunxi_chip);
/*request irq*/
if (sunxi_chip->irq_base >= 0) {
err = request_irq(GPIO_IRQ_NO, sunxi_gpio_irq_handler,
IRQF_SHARED, "sunxi-gpio", sunxi_chip);
if (err) {
pr_err("Can't request irq %d\n", GPIO_IRQ_NO);
goto irqchip;
}
}
/* register a gpio_chip*/
err = gpiochip_add(&sunxi_chip->chip);
if (err < 0)
goto irqhdl;
/*save gpioprivate data,we cat get these data like this : platform_get_drvdata()*/
platform_set_drvdata(pdev, sunxi_chip);
return 0;
irqhdl:
if (sunxi_chip->irq_base >= 0)
free_irq(GPIO_IRQ_NO, sunxi_chip);
irqchip:
sunxi_gpio_irq_remove(sunxi_chip);
if (sunxi_chip->irq_base >= 0)
irq_free_descs(sunxi_chip->irq_base, EINT_NUM);
unmap:
iounmap(sunxi_chip->gaddr);
exit:
kfree(sunxi_chip);
kfree(pnames);
return err;
}
在这里,我只是追到了一些资源的申请和注册,在/sys/class/gpio-sw/目录下可以使用open()wrte() read() ioctl() 这些函数来读取和操作GPIO的数据,但是,我在该驱动中并没发现这些函数的底层实现,这是个什么缘由呢?
谢谢!
页:
[1]