rk3128 控制GPIO

本篇主要讲在Android系统中的linux下控制GPIO的方法,android 通过jni控制GPIO可基于本篇内容继续开展;

linux控制GPIO基本上有两种方法,一是通过pinctrl体系,直接使用/sys下的文件进行控制,另一种就是编写驱动,在驱动中进行控制,下面分别进行介绍:
一、是用sys文件系统控制(更深入的介绍请移步:
http://blog.chinaunix.net/uid-27717694-id-3701921.html);
Sysfs路径 /sys/class/gpio有3个入口条目: - 控制接口用于用户空间获取GPIO控制 (export和unexport) - GPIO自己(gpioxx) - GPIO控制器(gpiochipxx)
这是对于标准文件的补充,包括“device”符号
控制接口是只写的: /sys/class/gpio/ export
例如:“echo 19 > export”将创建一个GPIO #19的“gpio19”节点(假设内核代码未申请此GPIO号)。 注意,此处返回错误基本上是因为内核驱动中使用了gpio_request占用或者获取了该GPIO
“unexport”————与“export”效果相反
例如:"echo 19 > unexport"将移除一个由“export”文件导出的“gpio19”节点。
GPIO信号拥有如/sys/class/gpio/gpio42/(对应于GPIO#42)的路径,并且具有下列读写属性: /sys/class/gpio/gpioN/
“direction”————读为“in”或是“out”。这个值通常可写。写“out”默认初始化此值为低。为了确定无障碍操作,值“low”和“high”可以被写入以配置GPIO的输出初始化值。
注意这个属性“将不存在”如果内核不支持改变一个GPIO的方向,或者它不能被内核代码导出(不能显式的允许用户空间来重新配置GPIO的选项。)
“value”—————读作“0”(低)或“1”(高)。如果GPIO被配置为一个输出,这个值可写; 任何非零值均被视为高。 如果管脚可以被配置为中断产生中断管脚,且如果它已经被配置为产生中断(参考“edge”描述),你可以poll(2)此文件并且当中断触发时poll(2)将返回。如果你使用了poll(2),设置POLLPRI和POLLERR事件。如果你使用select(2),在exceptfds中设置文件描述符。在poll(2)返回之后,有两个选择一是lseek(2)到sysfs文件的开始且读新的值,另一个是关闭文件且重打开它来读取新的值。(为何这样设置?)
“edge”————读作“none”、“rising”、“falling”或是“both”。写这些字符串以选择边沿信号,他将使得“value”文件上的poll(2)操作返回。 这个文件只在管脚可以配置为中断产生输入管脚时存在。
“active_low”————读为0(false)或1(true)。写任何非零值都会反转读或写的值。目前和后来的poll(2)支持经由edge属性配置为“rising”或“falling”上升沿或下降沿将遵循这个设置。
GPIO控制器具有如/sys/class/gpio/gpiochip42/(针对控制器,实现GPIO开始于#42)的路径,且具有下列制度属性: /sys/class/gpio/gpiochipN/
“base”————与N相等,是第一个被此芯片管理的GPIO “label”————提供用于诊断(并不总是独一无二的) “ngpio”————管理的GPIO数(N到N+ngpio-1)
从内核代码中导出 --------------------------
内核代码可以显式管理那些使用gpio_request()申请的GPIO的导出 /* export the GPIO to userspace */ int gpio_export(unsigned gpio, bool direction_may_change);
/* reverse gpio_export() */ void gpio_unexport();
/* create a sysfs link to an exported GPIO node */ int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
/* change the polarity of a GPIO node in sysfs */ int gpio_sysfs_set_active_low(unsigned gpio, int value);

一个内核驱动申请一个GPIO后,它可以使用gpio_export()使得sysfs接口有效。驱动可以控制信号方向是否可以改变。这使得驱动可以防止用户空间代码不小心冲击重要的系统状态。
明确的exporting有助于调试(使得一些实验更简单),或是提供一个总是可以使用的接口,适合于bsp文档。
GPIO被导出后,gpio_export_link()允许在sysfs的任何地方创建GPIO sysfs节点的符号链接。驱动可以用此在它们自己设备sysfs目录下提供指定名字的接口(链接到GPIO节点)
驱动可以使用gpio_sysfs_set_active_low()隐藏GPIO在用户空间和单板之间的线极性不同。这仅影响sysfs接口。极性变换可以在gpio_export()之前和之后完成,并且前面使能的poll(2) (支持上升沿或下降沿事件)将被重新配置为遵循此设置。

二、编写驱动(rk3128为例,转载自:
http://developer.t-firefly.com/forum.php?mod=viewthread&tid=2436&highlight=gpio)

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct UserData{ int gpio; int state; }; static struct of_device_id luobogpio_of_match[] = { { .compatible = "luobogpio" }, { } }; MODULE_DEVICE_TABLE(of, luobogpio_of_match); static int luobogpio_open(struct inode *inode, struct file *filp) { printk("luobogpio_open\n"); return 0; }static ssize_t luobogpio_read(struct file *filp, char __user *ptr, size_t size, loff_t *pos) { if (ptr == NULL) printk("%s: user space address is NULL\n", __func__); return sizeof(int); }static long luobogpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { long ret = 0; struct UserData userdata; unsigned char label[10]; printk("luobogpio_ioctl: cmd = %d arg = %ld\n",cmd, arg); switch (cmd){case 0: printk("gpio_request\n"); if (copy_from_user((void*)&userdata,(void __user *)arg, sizeof(struct UserData))) return -EFAULT; printk("copy_from_usergpio=%d ,state=%d\n",userdata.gpio,userdata.state); sprintf(label,"gpio-%d",userdata.gpio); printk("----->%s\n",label); ret = gpio_request(userdata.gpio, label); if (ret) { printk("failed to request GPIO%d for you ret:%d\n",userdata.gpio,ret); } break; case 1:printk("gpio_direction_output\n"); if (copy_from_user((void*)&userdata,(void __user *)arg, sizeof(struct UserData))) return -EFAULT; printk("copy_from_usergpio=%d ,state=%d\n",userdata.gpio,userdata.state); ret=gpio_direction_output(userdata.gpio, userdata.state); if (ret) { printk("failed to gpio_direction_outputfor you ret:%d\n",userdata.gpio); } break; case 5: printk("gpio_free\n"); if (copy_from_user((void*)&userdata,(void __user *)arg, sizeof(struct UserData))) return -EFAULT; printk("copy_from_usergpio=%d ,state=%d\n",userdata.gpio,userdata.state); gpio_free(userdata.gpio); break; default: printk("unknown ioctl cmd!\n"); ret = -EINVAL; break; } return ret; }static int luobogpio_release(struct inode *inode, struct file *filp) { printk("luobogpio_release\n"); return 0; }static struct file_operations luobogpio_fops = { .owner= THIS_MODULE, .open= luobogpio_open, .read= luobogpio_read, .unlocked_ioctl= luobogpio_ioctl, .release = luobogpio_release, }; static struct miscdevice luobogpio_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "luobogpio", .fops = &luobogpio_fops, }; static int luobogpio_probe(struct platform_device *pdev) { int ret=-1; ret = misc_register(&luobogpio_dev); if (ret < 0){ printk("ac_usb_switch register err!\n"); return ret; }printk("func: %s\n", __func__); return 0; }static int luobogpio_remove(struct platform_device *pdev) { //printk("func: %s\n", __func__); return 0; }#ifdef CONFIG_PM_SLEEP static int luobogpio_suspend(struct device *dev) { //printk("func: %s\n", __func__); return 0; }static int luobogpio_resume(struct device *dev) { //printk("func: %s\n", __func__); return 0; } #endifstatic const struct dev_pm_ops luobogpio_pm_ops = { #ifdef CONFIG_PM_SLEEP .suspend = luobogpio_suspend, .resume = luobogpio_resume, .poweroff = luobogpio_suspend, .restore = luobogpio_resume, #endif }; static struct platform_driver luogpio_driver = { .driver= { .name= "luobogpio", .owner= THIS_MODULE, .pm= &luobogpio_pm_ops, .of_match_table= of_match_ptr(luobogpio_of_match), }, .probe= luobogpio_probe, .remove= luobogpio_remove, }; module_platform_driver(luogpio_driver); MODULE_DESCRIPTION("luobogpio Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:luobogpio");



【rk3128 控制GPIO】

    推荐阅读