1.问题:在全志方案中如果需要设置上拉或者下拉模式,需要在script.bin(先转换为script.fex)中配置gpio口 如:
但是配置好后是不会生效的,需要写一个驱动来通过读取这个文件的gpio配置来配置相应的寄存器。
代码:
#include <linux/init.h>
2 #include <linux/module.h>
3 #include <mach/sys_config.h>
4 #include <mach/pinctrl.h>
5 #include <asm/io.h>
6 #include <mach/gpio.h>
7
8 #define PIO_BASE 0x01c20800
9 typedef volatile unsigned int uint32;
10 typedef struct {
11 // gpio口的功能配置寄存器, 每个io口在配置寄存器里占用4位(实际用3位)
12 uint32 CFGs[4]; //4个功能配置寄存器,每个寄存配置8个io口
13
14 // gpio口的数据寄存器, 每个io口占用一位.
15 uint32 DAT;
16
17 // gpio口驱动电流配置寄存器, 每个io口占用2位
18 uint32 DRVs[2]; // 两个寄存器,每个寄存器配置16个io口
19
20 // gpio口上下拉配置寄存器, 每个io口占用2位
21 uint32 PULLs[2]; // 两个寄存器,每个寄存器配置16个io口
22
23 }PIO_t; //表示每组io口都有的配置寄存器
24
25
26 static PIO_t *pios[7]; // 每个元素分别存放PA, PB, PC, PD, PE, PF, PG组io口的寄存器地址
27 static u8 *vaddr;
28
29 static int __init h3gpio_init(void)
30 {
31 script_item_u *list;
32 int n, i, j, k;
33 int sel, pull, drv, level;
34
35 vaddr = ioremap(PIO_BASE, SZ_4K); //映射gpio配置寄存器的基地址
36 if (NULL == vaddr)
37 return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(pios); i++) //准备好每组io口的配置寄存器的地址
40 pios[i] = (PIO_t *)(vaddr+i*0x24);
41
42 // pa的配置寄存器0的地址 == &pios[0]->CFG0
43 n = script_get_pio_list("gpio_para", &list); //返回值为gpio口的个数
44 if (n <= 0)
45 return -ENODEV;
46
47 for (i = 0; i < n; i++)
48 {
49 //在内核里每组io口都算是32个一组,即使硬件上每组都没有32个io口那么多.
50 //所以list[i].gpio.gpio / 32 即可算出是第几组,
51 j = list[i].gpio.gpio >> 5; // pios[j]就是表示相应组的配置寄存结构体
52 k = list[i].gpio.gpio & 31; //算出在组内是第几个io口
53
54 sel = list[i].gpio.mul_sel; //script.bin里io功能选择
55 pull = list[i].gpio.pull; //上下拉功能
56 drv = list[i].gpio.drv_level; //驱动电流等级
57 level = list[i].gpio.data; //io口作输出时,输出什么电平
58
59 if (-1 != sel) //功能选择不是<default>
60 {
61 pios[j]->CFGs[k>>3] &= ~(0xf << ((k&7)<<2));
62 pios[j]->CFGs[k>>3] |= sel << ((k&7)<<2);
63
64 if (1 == sel) //如果是输出,还需指定输出的电平
65 {
66 pios[j]->DAT &= ~(1<<k);
67 pios[j]->DAT |= level << k;
68 }
69 }
70 if (-1 != pull) //上下拉功能不是<default>
71 {
72 pios[j]->PULLs[k>>4] &= ~(3 << ((k&15)<<1));
pios[j]->PULLs[k>>4] |= pull << ((k&15)<<1);
74 }
75
76 if (-1 != drv) //驱动电流等级不是<default>
77 {
78 pios[j]->DRVs[k>>4] &= ~(3 << ((k&15)<<1));
79 pios[j]->DRVs[k>>4] |= drv << ((k&15)<<1);
80 }
81 }
82
83 return 0;
84 }
85
86 static void __exit h3gpio_exit(void)
87 {
88 iounmap(vaddr);
89 }
90
91
92 module_init(h3gpio_init);
93 module_exit(h3gpio_exit);
94
95 MODULE_LICENSE("GPL");
2.Makefile 文件
1 KDIR := /home/edan/uboot_kernel/orangepi_sdk/source/linux-3.4.112
2 obj-m += gpio.o
3
4 export ARCH=arm
5 export CROSS_COMPILE=arm-linux-gnueabihf-
6
7 all:
8 make -C $(KDIR) modules M=`pwd`
9
10 .PHONY :clean
11 clean:
12
13 make -C $(KDIR) modules clean M=`pwd`