rk芯片驱动编写

gpio

设备树

在/下新建节点,因为没有复用需求所以不需要pinctrl

bash 复制代码
test{
			compatible = "rk,mytest";
			test-gpio = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>;
			status = "okay";
	};

驱动程序(mygpio.c)

cpp 复制代码
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of.h>

#define mygpio_CNT         1
#define mygpio_NAME        "mygpio"
#define LEDON               1
#define LEDOFF              0

struct mygpio_dev{
    dev_t devid;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    int major;
    int minor;
    struct device_node  *nd;
    int gpio_id;
};

struct mygpio_dev mygpio;

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

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

static ssize_t mygpio_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    int retvalue;
    unsigned char databuf[1];
    unsigned char gpiostat;
    struct mygpio_dev *dev = filp->private_data;

    retvalue = copy_from_user(databuf,buf,cnt);
    if(retvalue < 0){
        printk("kernel write failed!\r\n");
        return -EINVAL;
    }

    gpiostat = databuf[0];
    
    if(gpiostat == LEDON){
        gpio_set_value(dev->gpio_id,0);
    }else if(gpiostat == LEDOFF){
        gpio_set_value(dev->gpio_id,1);
    }
    return 0;
}

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


static struct file_operations mygpio_fops = {
    .owner = THIS_MODULE,
    .open  = mygpio_open,
    .read  = mygpio_read,
    .write = mygpio_write,
    .release = mygpio_release,
};

static int __init helloworld_init(void) //驱动入口函数
{
    int ret = 0;
    const char *str;
    /*使用设备树获取gpio节点*/
    mygpio.nd = of_find_node_by_path("/test");
    if(mygpio.nd == NULL){
        printk("mygpio node not find!\r\n");
        return -EINVAL;
    }else{
        printk("mygpio node find!\r\n");
    }

    ret = of_property_read_string(mygpio.nd,"test-gpio",&str);
    if(ret<0)
        return -EINVAL;

    ret = of_property_read_string(mygpio.nd,"compatible",&str);
    if(strcmp(str,"rk,mytest")){
        printk("rkgpio:Compatible match failed\n");
        return -EINVAL;
    }

    mygpio.gpio_id = of_get_named_gpio(mygpio.nd,"test-gpio",0);
    if(mygpio.gpio_id <0){
        printk("can't get test-gpio\r\n");
        return -EINVAL;
    }
    printk("test-gpio num = %d\r\n",mygpio.gpio_id);

    ret = gpio_direction_output(mygpio.gpio_id,1);
    if(ret < 0){
        printk("can't set gpio!\r\n");
        return -EINVAL;
    }

    if(mygpio.major){
        mygpio.devid = MKDEV(mygpio.major,0);
        register_chrdev_region(mygpio.devid,mygpio_CNT,mygpio_NAME);
    }else{
        alloc_chrdev_region(&mygpio.devid,0,mygpio_CNT,mygpio_NAME);
        mygpio.major = MAJOR(mygpio.devid);
        mygpio.minor = MINOR(mygpio.devid);
    }
    printk("major = %d,minor = %d",mygpio.major,mygpio.minor);
    
    mygpio.cdev.owner = THIS_MODULE;
    cdev_init(&mygpio.cdev,&mygpio_fops);
    cdev_add(&mygpio.cdev,mygpio.devid,mygpio_CNT);
    
    mygpio.class = class_create(THIS_MODULE,mygpio_NAME);
    if(IS_ERR(mygpio.class)){
        return PTR_ERR(mygpio.class);
    }

    mygpio.device = device_create(mygpio.class,NULL,mygpio.devid,NULL,mygpio_NAME);
    if(IS_ERR(mygpio.device)){
        return PTR_ERR(mygpio.device);
    }
    return 0;
    
    printk("gpio_init\r\n");//注意: 内核打印用 printk 而不是 printf
    return 0;
} 
static void __exit helloworld_exit(void) //驱动出口函数
{
    printk("helloworld_exit\r\n");
} 


module_init(helloworld_init); //告诉linux模块入口函数,加载模块代码到操作系统
module_exit(helloworld_exit); //卸载
MODULE_LICENSE("GPL v2"); //同意 GPL 开源协议
MODULE_VERSION("1.0"); //驱动的版本
MODULE_DESCRIPTION("helloworld Driver");  //lsmod

测试用应用程序(mygpioApp.c)

cpp 复制代码
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"


#define LEDOFF 	0
#define LEDON 	1

int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	unsigned char databuf[1];
	
	if(argc != 3){
		printf("Error Usage!\r\n");
		return -1;
	}

	filename = argv[1];

	/* 打开led驱动 */
	fd = open(filename, O_RDWR);
	if(fd < 0){
		printf("file %s open failed!\r\n", argv[1]);
		return -1;
	}

	databuf[0] = atoi(argv[2]);	/* 要执行的操作:打开或关闭 */

	/* 向/dev/led文件写入数据 */
	retvalue = write(fd, databuf, sizeof(databuf));
	if(retvalue < 0){
		printf("LED Control Failed!\r\n");
		close(fd);
		return -1;
	}

	retvalue = close(fd); /* 关闭文件 */
	if(retvalue < 0){
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	return 0;
}

Makefile

bash 复制代码
# 设置平台架构
export ARCH=arm
# 交叉编译器前缀(注意:原代码中=后有空格,这里修正为无空格,否则会报错)
export CROSS_COMPILE=/home/lubancat/rk3506/rk3506_linux6.1_bsp/prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-

# 驱动模块编译配置
obj-m := mygpio.o
# 内核源码目录
KDIR := /home/lubancat/rk3506/rk3506_linux6.1_bsp/build-iot_nand-evm/kernel
# 当前目录
PWD ?= $(shell pwd)

# 应用程序名称(可根据你的实际文件名修改)
APP_NAME := mygpioApp
# 应用程序源码文件(假设你的应用程序源码是 gpioApp.c,可根据实际修改)
APP_SRC := mygpioApp.c

# 核心目标:先编译驱动,再编译应用程序
all: modules app

# 编译驱动模块的规则
modules:
	make -C $(KDIR) M=$(PWD) modules

# 编译应用程序的规则
app:
	$(CROSS_COMPILE)gcc -o $(APP_NAME) $(APP_SRC) -Wall

# 清理规则:同时清理驱动和应用程序
clean:
	make -C $(KDIR) M=$(PWD) clean
	rm -rf $(APP_NAME)  # 删除编译出的应用程序可执行文件

移植到板子(/mnt)

1.将生成的.ko文件推送到设备:adb push hello.ko /mnt/hello.ko

  • 设置文件权限:chmod 777 /mnt/hello.ko

  • 加载模块:insmod ``/mnt/``hello.ko

  • 查看已加载模块:lsmod

platfrom

设备树

驱动程序

测试用应用程序

Makefile

irq

设备树

驱动程序

测试用应用程序

Makefile

iic

设备树

在编写设备树和映射设备树文件之后发现原先dtsi的引脚在我的板子上没有因此我们需要在dts里面重新写上pintcrl来实现硬件信息的覆盖

驱动程序

测试用应用程序

Makefile

spi

设备树

驱动程序

测试用应用程序

Makefile

gpio

设备树

驱动程序

测试用应用程序

Makefile

gpio

设备树

驱动程序

测试用应用程序

Makefile

gpio

设备树

驱动程序

测试用应用程序

Makefile

gpio

设备树

驱动程序

测试用应用程序

Makefile

gpio

设备树

驱动程序

测试用应用程序

Makefile

相关推荐
杨云龙UP3 分钟前
Oracle ASM磁盘组空间分配与冗余理解
linux·运维·数据库·sql·oracle
weixin_458872619 分钟前
东华复试OJ每日3题打卡·复盘103~105
学习
朽棘不雕15 分钟前
Linux权限
linux
minji...26 分钟前
Linux 库制作与原理(三)深入动静态链接原理
linux·运维·服务器·c++
SuniaWang34 分钟前
《Spring AI + 大模型全栈实战》学习手册系列 ·专题三:《Embedding 模型选型指南:从 MMTEB 排名到实际应用》
人工智能·学习·spring
问道飞鱼39 分钟前
【Tauri框架学习】Windows 11 环境下 Tauri 开发环境安装与问题解决手册
windows·学习·tauri·开发环境
bukeyiwanshui1 小时前
Linux实践
linux·运维·服务器
xlp666hub1 小时前
【Linux驱动实战】:字符设备之ioctl与mutex全解析
linux·面试
لا معنى له1 小时前
什么是Active Inference(主动推理)? ——学习笔记
笔记·学习
JicasdC123asd1 小时前
并行双分支瓶颈架构改进YOLOv26异构卷积核协同特征提取与残差学习双重突破
学习·yolo·架构