F1C200S挖坑日记(9)——IO口驱动(设备树)

一、修改设备树文件

这里为了以后方便开发,我将荔枝派的设备树文件复制了一份,并且改成了我自己的名字。

 然后在更改后的文件内添加自己需要的内容,比如我们这次使用的IO口信息。

 和非设备树方式的IO口驱动一样,以PE2为例进行实验。

二、编写设备树版本的IO口驱动

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define DTSIO_CNT 1
#define DTSIO_NAME "DTS_IO"

#define HIGH 1
#define LOW  0

static void __iomem *PE_CFG0;
static void __iomem *PE_DATA;

struct dtsio_dev
{
    /* data */
    dev_t devid;            //asd
    struct cdev cdev;
    struct class *class;
    struct device *device;
    int major;
    int minor;
    struct device_node *node;
};

struct dtsio_dev dtsio ;

void io_switch(u8 sta)
{
    u32 val=0;
    if(sta==HIGH)
    {
        val=readl(PE_DATA);
        val|= (1 << 2);
        writel(val, PE_DATA);
    }
    else if(sta==LOW)
    {
        val=readl(PE_DATA);
        val &= ~(1 << 2);
        writel(val, PE_DATA);
    }
}

static int io_open(struct inode *inode,struct file *filp)
{
    filp->private_data = &dtsio;
    return 0;
}

static ssize_t io_read(struct file *filp,char  __user *buf,size_t cnt,loff_t *offt)
{
    return 0;
}



static ssize_t io_write(struct file *filp,const char __user *buf,size_t cnt, loff_t *offt)
{
    int ret;
    unsigned char databuf[1];
    unsigned char io_sta;

    ret = copy_from_user(databuf,buf,cnt);
    if(ret<0)
    {
        printk("Kernel write failed!\r\n");
    }
    
    if(databuf[0]==HIGH)
    {
        io_switch(HIGH);
    }
    else if (databuf[0]==LOW)
    {
        io_switch(LOW);
    }
    
    return 0;
}

static int io_release(struct inode *inode,struct file *filp)
{
    return 0;
}


/*
* 设备操作函数结构体
*/
static struct file_operations dtsio_fops = {
    .owner = THIS_MODULE, 
    .open = io_open,
    .read = io_read,
    .write = io_write,
    .release = io_release,
};

/*
* @description : 驱动入口函数
 * @param : 无
* @return : 0 成功;其他 失败
*/
static int __init io_init(void)
{
    int ret;
    unsigned char i;
    unsigned int val;
    const char *str;
    unsigned int regdata[10];
    struct property *proper;

    dtsio.node = of_find_node_by_path("/testIO");
    if(dtsio.node == NULL)
    {
        printk("testIO node not found!\r\n");
        return -EINVAL;
    }
    else
    {
        printk("testIO node has been found!\r\n");
    }

    proper = of_find_property(dtsio.node,"compatible",NULL);
    if (proper == NULL)
    {
        printk("compatible property not found!\r\n");
    }
    else
    {
        printk("compatible = %s \r\n",(char *)proper->value);   
    }

    ret = of_property_read_string(dtsio.node,"status",&str);
    if(ret<0)
    {
        printk("test io status read failed!\r\n");
    }
    else
    {
        printk("status = %s \r\n",str);
    }
    
    ret = of_property_read_u32_array(dtsio.node,"reg",regdata,4);
    if(ret<0)
    {
        printk("reg property read failed!\r\n");
    }
    else
    {
        printk("reg data : \r\n");
        for(i=0;i<4;i++)
        {
            printk("%#x ",regdata[i]);
        }
        printk("\r\n");
    }

    PE_CFG0  = of_iomap(dtsio.node,0); // ioremap(PIO_CFG0(PE),1);
    PE_DATA  = of_iomap(dtsio.node,1); //ioremap(PIO_DATE(PE),1);

    val =   readl(PE_CFG0);     //CFG
    //  printk(KERN_EMERG"PE_CFG0 = %x",val);
    val &= ~(0x07<<8);
    val |=  0x01<<8;
    writel(val,PE_CFG0);

    val =   readl(PE_DATA);     //PUL
    val |=  0x00<<4;                //00 disable 01 pull-up 10 pull-down 11 reserved
    writel(val,PE_DATA);

    if(dtsio.major)
    {
        dtsio.devid = MKDEV(dtsio.major,0);
        register_chrdev_region(dtsio.devid,DTSIO_CNT,DTSIO_NAME);
    }
    else
    {
        alloc_chrdev_region(&dtsio.devid,0,DTSIO_CNT,DTSIO_NAME);
        dtsio.major = MAJOR(dtsio.devid);
        dtsio.minor = MINOR(dtsio.devid);
    }
    printk("dtsio major = %d ,minor = %d \r\n",dtsio.major,dtsio.minor);

    dtsio.cdev.owner = THIS_MODULE;
    cdev_init(&dtsio.cdev,&dtsio_fops);

    cdev_add(&dtsio.cdev,dtsio.devid,DTSIO_CNT);

    dtsio.class = class_create(THIS_MODULE,DTSIO_NAME);
    if(IS_ERR(dtsio.class))
    {
        return PTR_ERR(dtsio.class);
    }

    dtsio.device = device_create(dtsio.class,NULL,dtsio.devid,NULL,DTSIO_NAME);
    if (IS_ERR(dtsio.device))
    {
        return PTR_ERR(dtsio.device);
    }
    


    return 0;
}

static void __exit io_exit(void)
{
    iounmap(PE_CFG0);
    iounmap(PE_DATA);

    cdev_del(&dtsio.cdev);
    unregister_chrdev_region(dtsio.devid,DTSIO_CNT);
    
    device_destroy(dtsio.class,dtsio.devid);
    class_destroy(dtsio.class);
}


module_init(io_init);
module_exit(io_exit);

/* 
* LICENSE 和作者信息
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Distance");



代码就不过多介绍了,请参考正点原子嵌入式驱动开发教程

三、遇到的问题

其中有两个需要注意的地方,我在过程中遇到了相关问题

1、在write函数中使用了copy_from_user函数,传入的databuf参数必须是一个数组,否则驱动运行报错

static ssize_t io_write(struct file *filp,const char __user *buf,size_t cnt, loff_t *offt)
{
    int ret;
    unsigned char databuf[1];
    unsigned char io_sta;

    ret = copy_from_user(databuf,buf,cnt);

2、在init函数中,使用了property指针,printk打印property内信息时,需要进行强制类型转换

static int __init io_init(void)
{
    int ret;
    unsigned char i;
    unsigned int val;
    const char *str;
    unsigned int regdata[10];
    struct property *proper;        /*注意这里*/

    ………………

    proper = of_find_property(dtsio.node,"compatible",NULL);
    if (proper == NULL)
    {
        printk("compatible property not found!\r\n");
    }
    else
    {
        printk("compatible = %s \r\n",(char *)proper->value);       /*注意这里*/
    }

    ………………
}

报错信息如下

 四、运行测试

测试应用程序和非设备树的应用程序通用,可以直接拿来测试。

我们测试过程如下,仅供参考,需要根据自己的实际情况进行调整。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Distance_90

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值