内核里gpiolib可以操作gpio口,但基本只能作输入或输出功能。而全志的gpio控制器除这两种功能外,还提供了其它功能,如配置gpio的上下拉,输出电流等级大小等。所以全志提供了类似gpiolib但可以有更多功能的驱动(但现版本的驱动也只实现输入和输出功能).
首先确认内核里是否已选择上gpio-sunxi功能(默认是已选择上的)
make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
Device Drivers --->
*- GPIO Support --->
<M> SUNXI GPIO USER INTERFACE
编译内核模块后,需要通过make modules_install安装模块到文件系统.
gpio-sunxi会像gpiolib一样提供gpio口操作的属性文件, 但无需提供gpio口的序号。只需要把要操作的gpio口列在script.bin里的gpio_para部分即可,gpio-sunxi驱动会在初始化时会给这些gpio口提供相应的属性文件.
如我的script.bin关于gpio_para部分的内容:
221 [gpio_para]
222 gpio_used = 1
223 gpio_num = 20
224 gpio_pin_1 = port:PA06<1><default><default><0>
225 gpio_pin_2 = port:PA13<1><default><default><0>
226 gpio_pin_3 = port:PA14<1><default><default><0>
227 gpio_pin_4 = port:PA01<1><default><default><0>
228 gpio_pin_5 = port:PD14<1><default><default><0>
229 gpio_pin_6 = port:PA00<1><default><default><0>
230 gpio_pin_7 = port:PA03<1><default><default><0>
231 gpio_pin_8 = port:PC04<1><default><default><0>
232 gpio_pin_9 = port:PC07<1><default><default><0>
233 gpio_pin_10 = port:PA02<1><default><default><0>
234 gpio_pin_11 = port:PA21<1><default><default><0>
235 gpio_pin_12 = port:PA07<1><1><3><0>
236 gpio_pin_13 = port:PA08<1><1><3><0>
237 gpio_pin_14 = port:PG08<1><default><default><0>
238 gpio_pin_15 = port:PA09<1><1><3><0>
239 gpio_pin_16 = port:PA10<1><1><3><0>
240 gpio_pin_17 = port:PG09<1><default><default><0>
241 gpio_pin_18 = port:PG06<1><default><default><0>
242 gpio_pin_19 = port:PG07<1><default><default><0>
243 gpio_pin_20 = port:PA15<1><default><default><0>
244
245 [leds_para]
246 leds_used = 0
247 green_led = port:PL10<1><default><default><1>
248 green_led_active_low = 0
249 red_led = port:PA15<1><default><default><0>
250 red_led_active_low = 0
//需要注意的地方, gpio_para里列出的gpio口会作gpio_request操作的,不可复用,所以leds_para的leds_used设0.
操作:
1 加载gpio-sunxi.ko驱动模块:
modprobe gpio-sunxi.ko
2 加载驱动模块后, 在/sys/class/gpio_sw目录下会看到上面所列的gpio口子目录:
/ # ls /sys/class/gpio_sw/P
PA0/ PA10/ PA14/ PA2/ PA3/ PA7/ PA9/ PC7/ PG6/ PG8/
PA1/ PA13/ PA15/ PA21/ PA6/ PA8/ PC4/ PD14/ PG7/ PG9/
3 每个gpio口子目录下又提供了属性文件:
cfg , data , pull, drv
// cfg属性文件是用于指定和获取gpio口的功能
// data属性文件用于提定和获取gpio口的电平作用
// pull属性文件用于设置gpio口的上下拉功能(现只有接口,没有实现此功能)
// pull属性文件用于设置gpio口的输出电流等级(现只有接口,没有实现此功能)
以上属性文件具体的可用值,应是根据datasheet来设置,如P15的配置信息:
功能分配(PA15): 000:输入, 001:输出, 010:SPI1_MOSI
011:UART3_RTS , 110:PA_EINT15, 111:IO Disable
默认值:7
内部电阻状态(PA15): 00: Pull-up/down disable , 01: Pull-up
10: Pull-down, 11: Reserved
默认值:0
驱动能力(指输出的电流大小,等级越高,电流越大):
00: Level 0 , 01: Level 1
10: Level 2 , 11: Level 3
默认值: 1
输出电平状态: 当功能选择输出时,1表示输出高电平, 0表示输出低电平
/////////////////////////
如操作PA15引脚(status-led用的gpio口)
echo 1 > /sys/class/gpio_sw/PA15/cfg //作输出功能
echo 1 > /sys/class/gpio_sw/PA15/data //输出高电平(灯亮)
echo 0 > /sys/class/gpio_sw/PA15/data //输出低电平(灯灭)
驱动源码在drivers/gpio/gpio-sunxi.c里
工作原理分析:
//已声明好4个属性文件, 每个属性文件都指定好读写操作的函数
279 static struct device_attribute gpio_sw_class_attrs[] = {
280 __ATTR(cfg, 0664, cfg_sel_show, cfg_sel_store),
281 __ATTR(pull, 0664, pull_show, pull_store),
282 __ATTR(drv, 0664, drv_level_show, drv_level_store),
283 __ATTR(data, 0664, data_show, data_store),
284 __ATTR_NULL,
285 };
653 module_init(gpio_sw_init); //驱动模块的初始化函数为gpio_sw_init
515 static int __init gpio_sw_init(void)
516 {
...
525 gpio_sw_class = class_create(THIS_MODULE, "gpio_sw"); //创建class成功后会在/sys/class/目录下生成一个gpio_sw子目录
...
531 gpio_sw_class->dev_attrs = gpio_sw_class_attrs; //指定了gpio_sw的子目录属性文件(cfg,pull,data,drv)
...
545 cnt = script_get_pio_list("gpio_para", &list); //获取script.bin里gpio_para里指定的所有gpio口
563 for(i=0;i<cnt;i++){ //遍历gpio_para里的gpio口,进行gpio_request操作和给每个gpio口生成一个platform_device对象,初始化platform_device对象及注册.
564 printk("gpio_pin_%d(%d) gpio_request\n",i+1, list[i].gpio.gpio);
565 if(gpio_request(list[i].gpio.gpio, NULL)){ //请求操作
566 printk("gpio_pin_%d(%d) gpio_request fail \n",i+1, list[i].gpio.gpio);
567 continue;
568 }
569 sw_pdata[i] = kzalloc(sizeof(struct sw_gpio_pd), GFP_KERNEL); //准备platform_data空间
570 if(!sw_pdata[i]){
571 printk(KERN_ERR "kzalloc fail for sw_pdata[%d]\n",i);
572 return -1;
573 }
574
575 gpio_sw_dev[i] = kzalloc(sizeof(struct platform_device), GFP_KERNEL); //创建platform_device对象
576 if(!gpio_sw_dev[i]){
577 printk(KERN_ERR "kzalloc fail for gpio_sw_dev[%d]\n",i);
578 return -1;
579 }
580
581 sprintf(sw_pdata[i]->name,"gpio_pin_%d",i+1);
582 if (normal_led_pin.str && !strcmp(sw_pdata[i]->name, normal_led_pin.str)) {
583 sprintf(sw_pdata[i]->link,"%s", "normal_led");
584 } else if (standby_led_pin.str && !strcmp(sw_pdata[i]->name, standby_led_pin.str)) {
585 sprintf(sw_pdata[i]->link,"%s", "standby_led");
586 }
587
//初始化platform_device对象
588 gpio_sw_dev[i]->name = "gpio_sw";
589 gpio_sw_dev[i]->id = i;
590 gpio_sw_dev[i]->dev.platform_data = sw_pdata[i];
591 gpio_sw_dev[i]->dev.release = gpio_sw_release;
592
593 if(platform_device_register(gpio_sw_dev[i])){ //注册platform_device对象
594 printk(KERN_ERR "%s platform_device_register fail\n",sw_pdata[i]->name);
595 goto INIT_ERR_FREE;
596 }
597 }
598 if(platform_driver_register(&gpio_sw_driver)){ //注册platform_driver对象
599 printk(KERN_ERR "gpio user platform_driver_register fail\n");
600 for(i=0;i<cnt;i++)
601 platform_device_unregister(gpio_sw_dev[i]);
602 goto INIT_ERR_FREE;
603 }
gpio_sw_driver对象:
504 static struct platform_driver gpio_sw_driver = {
505 .probe = gpio_sw_probe,
506 .remove = gpio_sw_remove,
507 .suspend = gpio_suspend,
508 .resume = gpio_resume,
509 .driver = {
510 .name = "gpio_sw", //按此名字进行匹配
511 .owner = THIS_MODULE,
512 },
513 };
416 static int __devinit gpio_sw_probe(struct platform_device *dev)
417 {
418 struct sw_gpio *sw_gpio_entry;
419 struct sw_gpio_pd *pdata = dev->dev.platform_data;
420 int ret;
421 unsigned long flags;
422 script_item_value_type_e type;
423 char io_area[16];
424
425 sw_gpio_entry = kzalloc(sizeof(struct sw_gpio), GFP_KERNEL); //驱动给每个设备准备的数据
426 if(!sw_gpio_entry)
427 return -ENOMEM;
428 sw_gpio_entry->class.item = \
429 kzalloc(sizeof(script_item_u), GFP_KERNEL);
430 if(!sw_gpio_entry->class.item) {
431 kfree(sw_gpio_entry);
432 return -ENOMEM;
433 }
434 //在script.bin的gpio_para里获取"port:PA15<1><default><default><0>"指定的配置功能,上下拉功能,输出电流等级等
435 type = script_get_item("gpio_para", pdata->name, sw_gpio_entry->class.item);
436 if(SCIRPT_ITEM_VALUE_TYPE_PIO != type){
437 printk(KERN_ERR "get config err!\n");
438 kfree(sw_gpio_entry->class.item);
439 kfree(sw_gpio_entry);
440 return -ENOMEM;
441 }
442
443 ret = mapGpioToName(io_area,sw_gpio_entry->class.item->gpio.gpio);
444 printk("gpio name is %s, ret = %d\n",io_area, ret); //获取名称: PA15
445
446 platform_set_drvdata(dev,sw_gpio_entry); //把给设备准备的数据绑定到设备
...
//初始化里的操作函数,在上面的属性文件操作函数里会调用这些gpio_sw_xxx_xxx函数来完成实际功能.
457 sw_gpio_entry->class.gpio_sw_cfg_set = gpio_sw_cfg_set;
458 sw_gpio_entry->class.gpio_sw_cfg_get = gpio_sw_cfg_get;
459 sw_gpio_entry->class.gpio_sw_pull_set = gpio_sw_pull_set;
460 sw_gpio_entry->class.gpio_sw_pull_get = gpio_sw_pull_get;
461 sw_gpio_entry->class.gpio_sw_drv_set = gpio_sw_drv_set;
462 sw_gpio_entry->class.gpio_sw_drv_get = gpio_sw_drv_get;
463 sw_gpio_entry->class.gpio_sw_data_set = gpio_sw_data_set;
464 sw_gpio_entry->class.gpio_sw_data_get = gpio_sw_data_get;
...
// gpio_sw_classdev_register其实就是在/sys/class/gpio_sw目录下创建子目录,并在每个子目录都会生成cfg,pull,drv,data等属性文件
472 ret = gpio_sw_classdev_register(&dev->dev, &sw_gpio_entry->class);
...
486 return 0;
487 }
如对cfg进行写操作时,则触发调用cfg_sel_store函数
188 static ssize_t cfg_sel_store(struct device *dev,
189 struct device_attribute *attr, const char *buf, size_t size)
190 {
191 struct gpio_sw_classdev *gpio_sw_cdev = dev_get_drvdata(dev); //获取驱动里给设备准备的数据
192 ssize_t ret = -EINVAL;
193 char *after;
194 int cfg = simple_strtoul(buf, &after, 10);
195 size_t count = after - buf;
196
197 if (isspace(*after))
198 count++;
199
200 if (count == size){
201 ret = count;
202 gpio_sw_cdev->gpio_sw_cfg_set(gpio_sw_cdev, cfg); //调用457行初始化的函数
203 }
204
205 return ret;
206 }
//然后通过阅读以下代码就可以发现有pull, drv接口,但根本没有实现实际功能.
79 static int
80 gpio_sw_cfg_set(struct gpio_sw_classdev *gpio_sw_cdev,int mul_cfg){
81
82 if (mul_cfg==0)
83 gpio_direction_input(gpio_sw_cdev->item->gpio.gpio);
84 else
85 gpio_direction_output(gpio_sw_cdev->item->gpio.gpio, 0);
86
87 return 0;
88 }
89
90 static int
91 gpio_sw_cfg_get(struct gpio_sw_classdev *gpio_sw_cdev){
92
93 return 0;
94 }
95
96 static int
97 gpio_sw_pull_set(struct gpio_sw_classdev *gpio_sw_cdev,int pull){
98
99 return 0;
100 }
101
102 static int
103 gpio_sw_pull_get(struct gpio_sw_classdev *gpio_sw_cdev){
104
105 return 0;
106 }
107
108 static int
109 gpio_sw_drv_set(struct gpio_sw_classdev *gpio_sw_cdev,int drv){
110
111 return 0;
112 }
113
114 static int
115 gpio_sw_drv_get(struct gpio_sw_classdev *gpio_sw_cdev){
116
117 return 0;
118 }
119
120 static int
121 gpio_sw_data_set(struct gpio_sw_classdev *gpio_sw_cdev,int data){
122 __gpio_set_value(gpio_sw_cdev->item->gpio.gpio,data);
123 return 0;
124 }
125
126 static int
127 gpio_sw_data_get(struct gpio_sw_classdev *gpio_sw_cdev){
128 return __gpio_get_value(gpio_sw_cdev->item->gpio.gpio);
129 }