【BeagleBone Black Rev. C试用体验】+设备树驱动

来源:互联网 发布:python tcp 保持连接 编辑:程序博客网 时间:2024/06/09 20:19
感觉设备树写驱动是未来的潮流。。。下面我们来讲讲设备树驱动开发。。

设备树语法我们这就不说了,去下面链接自己参考吧:
http://www.cnblogs.com/xiaojiang1025/p/6131381.html


一、修改设备树:
设备树文件在arch/arm/boot/dts目录下am335x-boneblack.dts文件

先贴代码:
/* add by Sourcelink */
/ {
        model = "TI AM335x BeagleBoneBlack";
        compatible = "ti,am335x-bone", "ti,am33xx";

        cpus {
                cpu@0 {
                        cpu0-supply = <&dcdc2_reg>;
                };
        };
       
        /* add by Sourcelink */
        source_gpio {
                        compatible = "sourcelink_gpio";
                        pinctrl-names = "sourcelink_gpio";
                        pinctrl-0 = <&sourcelink_pin>;
                        source_gpios = <&gpio2 12 0>;
        };
};

&am33xx_pinmux {
        rstctl_pins: pinmux_rstctl_pins {
                pinctrl-single,pins = <
                        /* eMMC_RSTn */
                        0x50 0x17        /* gpmc_a4.gpio1_20, OUTPUT | MODE7 | PULLUP */
                >;
        };

        /* add by Sourcelink */
        sourcelink_pin: pinmux_source_pins {
                pinctrl-single,pins = <
                        0x30 0x7        /* gpmc_ad12.gpio1_12, OUTPUT | MODE7 */
                >;
        };       
};
修改的地方我都有标注。。。
compatible是用来匹配的。。。
pinctrl-names用来匹配pinctrl设置信息。。。
source_gpios用来获取io信息。。。

我们用的是gpio1_12,设置mode7,且为输出模式。。。

切记gpio的地址标号是从1开始的。。。gpio1对应的是GPIO0_x的地址,我就是这出了问题一直没有调出来。。。


引脚的复用都是从800h地址开始:

对应管脚从gpio0_0开始四个字节开始增加,所以gpio1_12偏移对应:4*12 = 48 = 0x30


二、总线驱动
platform总线驱动这里就不介绍了。我也讲不明白。感兴趣的可以去 了解,以前学习的时候都是自己写个device再写个driver然后匹配。
现在有设备树了devcie省去了,减少了很大的代码冗余。。。。

写驱动编译有错误不要紧,一条条出解决,查问题。这个驱动刚写好时,一编译刷刷的一排error下来,看到额眼睛都花了,但是一个个看过去还是能解决的。无非就是头文件没包含
语法有问题。。调用的变量类型有问题。。

下面贴个简单的框架:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pinctrl/consumer.h>



static int gpio_drv_open(struct inode *inode, struct file *file)
{

        return 0;
}

static ssize_t gpio_drv_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
        int ret;
       
        return ret;
}


struct file_operations gpio_drv_fops = {
                .owner = THIS_MODULE,
                .open = gpio_drv_open,
                .write = gpio_drv_write,

};



static const struct of_device_id of_gpio_fortree_match[] = {
        { .compatible = "sourcelink_gpio", },
        {},
};


static int gpio_fortree_probe(struct platform_device *pdev)
{
       
       
        return 0;
}



static int gpio_fortree_remove(struct platform_device *pdev)
{
       
        return 0;
}



static struct platform_driver gpio_fortree_driver = {
        .probe                = gpio_fortree_probe,
        .remove                = gpio_fortree_remove,
        .driver                = {
                .name        = "sourcelink_gpio",
                .owner        = THIS_MODULE,
                .of_match_table = of_match_ptr(of_gpio_fortree_match),
        },
};


static int gpio_fortree_init(void)
{
        int ret;


        return ret;
}



static void gpio_fortree_exit(void)
{

}



module_init(gpio_fortree_init);
module_exit(gpio_fortree_exit);


MODULE_AUTHOR("Sourcelink");
MODULE_DESCRIPTION("device tree driver");
MODULE_LICENSE("GPL");

接下来就是填充代码了,先填充probe函数,再填充remove函数,接下来注册init和exit函数。。
最后把file_operations结构体填充完。。

完整代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pinctrl/consumer.h>


static int source_gpio;
static struct cdev  gpio_drv_cdev;   //内核中用cdev描述一个字符设备
static struct class *gpio_drv_class;
static int minor;
static int gpio_drv_open(struct inode *inode, struct file *file)
{
        minor = iminor(inode);    /* 获取文件的次设备号 */
       
    printk("gpio_drv_open\n");
        printk("minor:%d \n", minor);
        return 0;
}

static ssize_t gpio_drv_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
        int ret = 0;
        int val = 0;
       
        // 返回错误个数,正确返回0
        if (copy_from_user((int *)&val, user_buf, count)) {
                ret = -EFAULT;
        } else {
                *ppos += count;
                ret = count;
        }
       
        printk("val:%d \n", val);
        if (val == 1) {
                switch(minor){
                        case 0:
                    gpio_set_value(source_gpio, 1);
                                printk("gpio_on\n");
            break;
                }
        } else {
                switch(minor){
                        case 0:
                    gpio_set_value(source_gpio, 0);
                                printk("gpio_off\n");
                break;
                }
        }
       
        return ret;
}


struct file_operations gpio_drv_fops = {
                .owner = THIS_MODULE,
                .open = gpio_drv_open,
                .write = gpio_drv_write,

};



static const struct of_device_id of_gpio_fortree_match[] = {
        { .compatible = "sourcelink_gpio", },
        {},
};


static int  major;
static int gpio_fortree_probe(struct platform_device *pdev)
{
        struct device *dev = &pdev->dev;
    dev_t devid;
    struct pinctrl *pctrl;
    struct pinctrl_state *pstate;

        printk("enter %s\n",__func__);
       
    pctrl = devm_pinctrl_get(dev);
    if(pctrl == NULL)
    {
        printk("devm_pinctrl_get error\n");
    }
    pstate = pinctrl_lookup_state(pctrl, "sourcelink_gpio");
    if(pstate == NULL)
    {
        printk("pinctrl_lookup_state error\n");
    }
    pinctrl_select_state(pctrl, pstate);        /* gpmc_a12.gpio1_12, OUTPUT | MODE7 */

        source_gpio = of_get_named_gpio(dev->of_node, "source_gpios", 0);

        if (source_gpio <= 0) {
                printk("of_get_named_gpio error!!!\n");
                return -EINVAL;
        } else {
                printk("sourcelink_gpio is %d\n", source_gpio);
                if (devm_gpio_request_one(dev, source_gpio, GPIOF_OUT_INIT_LOW, "source_gpio44") != 0) {
                        printk("devm_gpio_request_one error!!!\n");
                }               
        }

       
         if(alloc_chrdev_region(&devid, 0, 1, "sourcelink") < 0)/* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
    {
        printk("%s ERROR\n",__func__);
        goto error;
    }
         
    major = MAJOR(devid);                     

    cdev_init(&gpio_drv_cdev, &gpio_drv_fops);                                                //绑定文件操作函数
    cdev_add(&gpio_drv_cdev, devid, 1);                                                                      //注册到内核

    gpio_drv_class = class_create(THIS_MODULE, "sourcelink");                         //创建sourcelink类,向类中添加设备,mdev会帮我们创建设备节点
    device_create(gpio_drv_class, NULL, MKDEV(major, 0), NULL, "source_gpio44");


        return 0;
       
error:
    unregister_chrdev_region(MKDEV(major, 0), 1);
       
        return -EINVAL;
}



static int gpio_fortree_remove(struct platform_device *pdev)
{
        printk("enter %s\n",__func__);

        device_destroy(gpio_drv_class, MKDEV(major, 0));

        class_destroy(gpio_drv_class);
       
        cdev_del(&gpio_drv_cdev);

        unregister_chrdev_region(MKDEV(major, 0), 1);
       
        return 0;
}



static struct platform_driver gpio_fortree_driver = {
        .probe                = gpio_fortree_probe,
        .remove                = gpio_fortree_remove,
        .driver                = {
                .name        = "sourcelink_gpio",
                .owner        = THIS_MODULE,
                .of_match_table = of_match_ptr(of_gpio_fortree_match),
        },
};


static int gpio_fortree_init(void)
{
        int ret;

        printk("enter %s\n",__func__);
        ret = platform_driver_register(&gpio_fortree_driver);
           if (ret)
                   printk(KERN_ERR "gpio_fortree_probe: probe failed: %d\n", ret);

        return ret;
}



static void gpio_fortree_exit(void)
{
        printk("enter %s\n",__func__);
        platform_driver_unregister(&gpio_fortree_driver);
}



module_init(gpio_fortree_init);
module_exit(gpio_fortree_exit);


MODULE_AUTHOR("Sourcelink");
MODULE_DESCRIPTION("device tree driver");
MODULE_LICENSE("GPL");
驱动我写了很多打印函数。。很方便调试。。

printk函数的打印信息是通过串口打印出来的。
还要改下打印级别:
echo 5 > /proc/sys/kernel/printk

用源码的调试吧。。

测试代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>



int main(int argc, char **argv)
{
        int fd;
        int led_state = 0;
        int i;


        fd = open("/dev/source_gpio44", O_RDWR);

        if (fd < 0)
                printf("can't open!\n");
#if 0

        if (argc != 2) {
                printf("Usage: \n");
                printf("%s <on|off>\n", argv[0]);
                return -1;
        }

        if (strcmp(argv[1], "on") == 0)
                led_state = 1;
        else
                led_state = 0;


        if (write (fd, &led_state, 1)) {
                printf("write successful!\n");
        }

#else
        for (i = 0; i < 10; i++) {
                switch (led_state) {
                        case 0:
                                write (fd, &led_state, 1);
                                printf("led off!\n");
                                led_state = 1;
                        break;
                        case 1:
                                write (fd, &led_state, 1);
                                printf("led on!\n");
                                led_state = 0;
                        break;
                }
                sleep(1);
        }

#endif

        close(fd);

        return 0;
}




阅读全文
0 0
原创粉丝点击