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_user  gpio=%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_user  gpio=%d ,state=%d\n",userdata.gpio,userdata.state);
                            ret=gpio_direction_output(userdata.gpio, userdata.state);
                                  if (ret) {
                                printk("failed to gpio_direction_output  for 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_user  gpio=%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;
}
#endif

static 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");


 

你可能感兴趣的:(android平台开发)