六、imx6ull驱动实现

一、硬件原理图阅读

二、GPIO相关寄存器介绍

1.管脚功能模式

2.管脚输入输出

3.管脚高低电平

三、寄存器操作

1.物理地址映射成虚拟地址

void __iomem *ioremap(phys_addr_t addr, size_t size);

参数:

@addr 物理地址

@size 物理地址大小

返回值:

成功返回虚拟地址,失败返回NULL

2.寄存器读写函数

#include <linux/io.h>

unsigned int readl (volatile void __iomem *addr ) //读4字节

void writel (unsigned int data,volatile void __iomem *addr) //写4字节

四、驱动源码

cpp 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <asm/io.h>
//LED 灯的寄存器设置
#define LED_MUXIO_REGPHY_ADDR 0x20E00B0
#define LED_MUXIO_REG_SIZE           0x4
#define LED_GPIO_BASE_ADDR          0x209C000
#define LED_GPIO_ADDR_SIZE            0x8
#define GPIO_DATREG_OFFSET           0x0
#define GPIO_DIRREG_OFFSET            0x4

#define LED_DEVICE_MAJOR 240
#define LED_DEVICE_MINOR 0

#define LED_DEVICE_ON _IO('L',0x01)
#define LED_DEVICE_OFF _IO('L',0x02)

MODULE_LICENSE("GPL v2");

struct led_device
{
    dev_t devid;
    void *gpio_muxio_reg;
    void *gpio_con_reg;
    struct device *dev;
    struct class *class;
    struct cdev led_cdev;
};
struct led_device *pled;

void led_init(void)
{
    int regval = readl(pled->gpio_muxio_reg);
    regval &= ~(0xf << 0);
    regval |= (0x5 << 0);
    writel(regval,pled->gpio_muxio_reg  );

    regval = readl(pled->gpio_con_reg + GPIO_DIRREG_OFFSET);
    regval |= (1 << 27);//第27位设1
    writel(regval,pled->gpio_con_reg + GPIO_DIRREG_OFFSET);
    return;
}

void led_on(void)
{
     int regval = readl(pled->gpio_con_reg + GPIO_DATREG_OFFSET);
     regval |= (1 << 27);
     writel(regval,pled->gpio_con_reg + GPIO_DATREG_OFFSET);
     return;
}

void led_off(void)
{
     int regval = readl(pled->gpio_con_reg + GPIO_DATREG_OFFSET);
     regval &=  ~(1 << 27);
     writel(regval,pled->gpio_con_reg + GPIO_DATREG_OFFSET);
    return;
}

static int led_device_open(struct inode *inode,struct file *file)
{
    printk("led device open\n");
    pled->gpio_muxio_reg = ioremap(LED_MUXIO_REGPHY_ADDR,LED_MUXIO_REG_SIZE);
    if(!pled->gpio_muxio_reg)
    {
        printk("Fail to ioremap LED_MUXIO_REGPHY_ADDR\n");
        return -ENOMEM;
    }
    pled->gpio_con_reg = ioremap(LED_GPIO_BASE_ADDR,LED_GPIO_ADDR_SIZE);
    if(!pled->gpio_con_reg)
    {
        printk("Fail to ioremap LED_GPIO_BASE_ADDR\n");
        return -ENOMEM;
    }
    led_init();
    return 0;
}
static int led_device_release(struct inode *inode,struct file *file)
{
printk("led device release\n");
led_off();
    iounmap(pled->gpio_muxio_reg);
    iounmap(pled->gpio_con_reg);
    return 0;
}

static long led_device_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
    switch (cmd)
    {
    case LED_DEVICE_ON:
        printk("led device on\n");
        led_on();
        break;
    case LED_DEVICE_OFF:
        printk("led device off\n");
        led_off();
        break;
    }
    return 0;
}

struct file_operations led_device_ops = {
    .owner = THIS_MODULE,
    .open = led_device_open,
    .release = led_device_release,
    .unlocked_ioctl = led_device_ioctl,
};

static int __init  led_driver_init(void)
{
    int err;
    
    pled = kmalloc(sizeof(*pled),GFP_KERNEL);
    if(pled == NULL)
    {
        printk("Fail to kmalloc\n");
        err = -ENOMEM;
        goto err_kmalloc;
    }
    //pled->led_cdev.ops = &led_device_ops;
    cdev_init(&pled->led_cdev,&led_device_ops);
#if 0
    pled->devid = MKDEV(LED_DEVICE_MAJOR,LED_DEVICE_MINOR);
    err = register_chrdev_region(pled->devid,1,"led-device");
    if(err)
    {
        printk("Fail to register_chrdev_region\n");
        kfree(pled);
    }
#endif
    err = alloc_chrdev_region(&pled->devid,0,1,"led-device");
    if(err)
    {
        printk("Fail to alloc_chrdev_region\n");
        goto err_alloc_chrdev_region;
      
    }
    printk("led device MAJOR:%d MINOR:%d\n",MAJOR(pled->devid),MINOR(pled->devid));

    err = cdev_add(&pled->led_cdev,pled->devid,1);
    if(err)
    {
        printk("Fail to cdev_add\n");
        goto err_cdev_add;
        
    }

    pled->class = class_create(THIS_MODULE,"imx6ull-leds");
    if (IS_ERR(pled->class))
    {
        err = PTR_ERR(pled->class);
        printk("Fail to class_create\n");
        goto err_class_create;
        
    }
    //
    pled->dev = device_create(pled->class,NULL,pled->devid,NULL,"led-device");
    if(IS_ERR(pled->dev))
    {
        printk("Fail to device_create\n");
        err = PTR_ERR(pled->dev);
        goto err_device_create;
        
    }
    
    return 0;
err_device_create:
    class_destroy(pled->class);
err_class_create:
    cdev_del(&pled->led_cdev);
err_cdev_add:
    unregister_chrdev_region(pled->devid,1);
err_alloc_chrdev_region:
    kfree(pled);
err_kmalloc:
    return err;
}

static void __exit  led_driver_exit(void)
{
    device_destroy(pled->class,pled->devid);
    class_destroy(pled->class);
    cdev_del(&pled->led_cdev);
    unregister_chrdev_region(pled->devid,1);
    kfree(pled);
    
}
module_init(led_driver_init);
module_exit(led_driver_exit);

五、应用程序源码

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define LED_DEVICE_ON _IO('L',0x01)
#define LED_DEVICE_OFF _IO('L',0x02)
int main(int argc,const char *argv[])
{
    int ret;
    int fd;
    fd = open("/dev/led-device",O_RDWR);
    if(fd < 0)
    {
        perror("Fail to open");
        return -1;
    }
    printf("open /dev/led-device success,fd:%d\n",fd);
    while (1)
    {
        ret = ioctl(fd,LED_DEVICE_ON);
        if(ret < 0)
        {
            perror("Fail to ioctl LED_DEVICE_ON\n");
            return -1;
        }
        sleep(1);
        ret = ioctl(fd,LED_DEVICE_OFF);
        if(ret < 0)
        {
            perror("Fail to ioctl LED_DEVICE_OFF\n");
            return -1;
        }
        sleep(1);
    }
    

    close(fd);
    return 0;
}
相关推荐
Johny_Zhao14 小时前
OpenClaw安装部署教程
linux·人工智能·ai·云计算·系统运维·openclaw
RuoZoe20 小时前
重塑WPF辉煌?基于DirectX 12的现代.NET UI框架Jalium
c语言
chlk1232 天前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑2 天前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件2 天前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
深紫色的三北六号3 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash3 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI3 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行4 天前
Linux和window共享文件夹
linux
木心月转码ing4 天前
WSL+Cpp开发环境配置
linux