CubieBoard中文论坛

 找回密码
 立即注册
搜索
热搜: unable
查看: 10443|回复: 1

cubieboard的uboot的GPIO的驱动详解

[复制链接]
发表于 2013-12-28 11:01:08 | 显示全部楼层 |阅读模式
转发自我的博客:http://blog.sina.com.cn/s/blog_b5020b670101ft49.html

uboot的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[4];
u32 dat;
u32 drv[2];
u32 pull[2];
};


struct sunxi_gpio_int {
u32 cfg[3];
u32 ctl;
u32 sta;
u32 deb;
};

struct sunxi_gpio_reg {
struct sunxi_gpio gpio_bank[9];
u8 res[0xbc];
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





回复

使用道具 举报

发表于 2014-1-4 22:13:46 | 显示全部楼层
LZ你好!我今天也在看全志A20 的gpio驱动。
【linux-3.4-cb2】
目录: driver/gpio/gpio-sunxi.c

------------------------
在这个驱动中,我看它使用的是platform平台设备相关编程。
-------------------------
由于是新手,其中有个疑点,还希望LZ能帮忙解答下。
--------------------------
首先,贴下代码:
  1. static int __init sunxi_gpio_init(void)
  2. {
  3.         int err = 0;
  4.         err = platform_device_register(&sunxi_gpio_device);
  5.         if (err)
  6.                 goto exit;

  7.         return platform_driver_register(&sunxi_gpio_driver);

  8. exit:
  9.         return err;
  10. }
  11. subsys_initcall(sunxi_gpio_init);
复制代码
------------------------
  1. static int __devinit sunxi_gpio_probe(struct platform_device *pdev)
  2. {
  3.         int i;
  4.         int err = 0;
  5.         int names_size = 0;
  6.         int gpio_used = 0;
  7.         int gpio_num = 0;
  8.         struct sunxi_gpio_data *gpio_i = NULL;
  9.         struct sunxi_gpio_data *gpio_data = NULL;
  10.         struct sunxi_gpio_chip *sunxi_chip = NULL;
  11.         char **pnames = NULL;

  12.         /* parse script.bin for [gpio_para] section
  13.            gpio_used/gpio_num/gpio_pin_x */

  14.         pr_info("sunxi_gpio driver init ver %s\n", SUNXI_GPIO_VER);

  15.        
  16.         err = script_parser_fetch("gpio_para", "gpio_used", &gpio_used,
  17.                                         sizeof(gpio_used)/sizeof(int));

  18.         if (err) {
  19.                 /* Not error - just info */
  20.                 pr_info("%s can't find script.bin '[gpio_para]' 'gpio_used'\n",
  21.                         __func__);
  22.                 return err;
  23.         }



  24.         if (!gpio_used) {
  25.                 pr_info("%s gpio_used is false. Skip gpio initialization\n",
  26.                         __func__);
  27.                 err = 0;
  28.                 return err;
  29.         }


  30.         err = script_parser_fetch("gpio_para", "gpio_num", &gpio_num,
  31.                                         sizeof(gpio_num)/sizeof(int));
  32.         if (err) {
  33.                 pr_err("%s script_parser_fetch '[gpio_para]' 'gpio_num' err\n",
  34.                         __func__);
  35.                 return err;
  36.         }

  37.         if (!gpio_num) {
  38.                 pr_info("%s gpio_num is none. Skip gpio initialization\n",
  39.                         __func__);
  40.                 err = 0;
  41.                 return err;
  42.         }

  43.        

  44.         /* Allocate memory for sunxi_gpio_chip + data/names array */
  45.         sunxi_chip = kzalloc(sizeof(struct sunxi_gpio_chip) +
  46.                                 sizeof(struct sunxi_gpio_data) * gpio_num,
  47.                                 GFP_KERNEL);

  48.        
  49.         gpio_data = (void *)sunxi_chip + sizeof(struct sunxi_gpio_chip);

  50.        

  51.         /* Allocate memory for variable array of fixed size strings */
  52.         /* in one chunk. This is to avoid 1+gpio_num kzalloc calls */
  53.         names_size = sizeof(*pnames) * gpio_num +
  54.                      sizeof(char) * MAX_GPIO_NAMELEN * gpio_num;


  55.         pnames = kzalloc(names_size, GFP_KERNEL);

  56.        
  57.         for (i = 0; i < gpio_num; i++) {
  58.                 pnames[i] = (void *)pnames + sizeof(*pnames) * gpio_num +
  59.                                 i * MAX_GPIO_NAMELEN;
  60.         }

  61.         if ((!pnames) || (!sunxi_chip)) {
  62.                 pr_err("%s kzalloc failed\n", __func__);
  63.                 err = -ENOMEM;
  64.                 goto exit;
  65.         }

  66.         /* Parse gpio_para/pin script data */
  67.         gpio_i = gpio_data;
  68.        
  69.         for (i = 0; i < gpio_num; i++) {

  70.                 sprintf(gpio_i->pin_name, "gpio_pin_%d", i+1);
  71.                 err = script_parser_fetch("gpio_para", gpio_i->pin_name,
  72.                                         (int *)&gpio_i->info,
  73.                                         sizeof(script_gpio_set_t));

  74.                 if (err) {
  75.                         pr_err("%s script_parser_fetch '[gpio_para]' '%s' err\n",
  76.                                 __func__, gpio_i->pin_name);
  77.                         break;
  78.                 }

  79.                 gpio_i++;
  80.         }
  81.        
  82. /*   i/o的物理地址映射到核心虚拟地址空间内 */
  83.         sunxi_chip->gaddr = ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE);

  84.        
  85.         if (!sunxi_chip->gaddr) {
  86.                 pr_err("Can't request gpio registers memory\n");
  87.                 err = -EIO;
  88.                 goto unmap;
  89.         }

  90.         sunxi_chip->dev                = &pdev->dev;
  91.         sunxi_chip->data        = gpio_data;
  92.         sunxi_chip->chip        = template_chip;
  93.         sunxi_chip->chip.ngpio        = gpio_num;
  94.         sunxi_chip->chip.dev        = &pdev->dev;
  95.         sunxi_chip->chip.label        = "A1X_GPIO";
  96.         sunxi_chip->chip.base        = 1;
  97.         sunxi_chip->chip.names        = (const char *const *)pnames;
  98.         sunxi_chip->irq_base        = -1;

  99.         /* configure EINTs for the detected SoC */
  100.         sunxi_gpio_eint_probe();

  101.         /* This needs additional system irq numbers (NR_IRQ=NR_IRQ+EINT_NUM) */
  102.         if (EINT_NUM > 0) {
  103.                 sunxi_chip->irq_base = irq_alloc_descs(-1, 0, EINT_NUM, 0);
  104.                 if (sunxi_chip->irq_base < 0) {
  105.                         pr_err("Couldn't allocate virq numbers. GPIO irq support disabled\n");
  106.                         err = sunxi_chip->irq_base;
  107.                 }
  108.         } else
  109.                 pr_info("GPIO irq support disabled in this platform\n");

  110. /*自旋锁初始化*/
  111.         spin_lock_init(&sunxi_chip->irq_lock);

  112. /*irq init*/
  113.         sunxi_gpio_irq_init(sunxi_chip);

  114. /*request irq*/
  115.         if (sunxi_chip->irq_base >= 0) {
  116.                 err = request_irq(GPIO_IRQ_NO, sunxi_gpio_irq_handler,
  117.                                   IRQF_SHARED, "sunxi-gpio", sunxi_chip);
  118.                 if (err) {
  119.                         pr_err("Can't request irq %d\n", GPIO_IRQ_NO);
  120.                         goto irqchip;
  121.                 }
  122.         }

  123. /* register a gpio_chip*/
  124.         err = gpiochip_add(&sunxi_chip->chip);

  125.         if (err < 0)
  126.                 goto irqhdl;
  127. /*save gpio  private data,we cat get these data like this : platform_get_drvdata()*/
  128.         platform_set_drvdata(pdev, sunxi_chip);
  129.         return 0;

  130. irqhdl:
  131.         if (sunxi_chip->irq_base >= 0)
  132.                 free_irq(GPIO_IRQ_NO, sunxi_chip);
  133. irqchip:
  134.         sunxi_gpio_irq_remove(sunxi_chip);
  135.         if (sunxi_chip->irq_base >= 0)
  136.                 irq_free_descs(sunxi_chip->irq_base, EINT_NUM);
  137. unmap:
  138.         iounmap(sunxi_chip->gaddr);
  139. exit:
  140.         kfree(sunxi_chip);
  141.         kfree(pnames);

  142.         return err;
  143. }
复制代码
在这里,我只是追到了一些资源的申请和注册,在  /sys/class/gpio-sw/  目录下可以使用open()  wrte() read() ioctl() 这些函数来读取和操作GPIO的数据,但是,我在该驱动中并没发现这些函数的底层实现,这是个什么缘由呢?

谢谢!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|粤ICP备13051116号|cubie.cc---深刻的嵌入式技术讨论社区

GMT+8, 2024-3-29 01:10 , Processed in 0.021202 second(s), 15 queries .

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc. | Style by Coxxs

返回顶部