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

相关推荐
知识分享小能手3 分钟前
Hadoop学习教程,从入门到精通, Hadoop 3.x 高可用集群 — 知识点详解(6)
大数据·hadoop·学习
毒爪的小新5 分钟前
Open WebUI 从零到一:打造属于你的私人ChatGPT
linux·ai·语言模型·chatgpt·openwebui
keyipatience8 分钟前
命名管道:跨进程通信的终极指南
linux·运维·服务器
searchforAI13 分钟前
坚持用AI做笔记,我的知识留存与学习速度大幅提升
人工智能·笔记·学习·ai·知识图谱·知识管理
Chris _data1 小时前
c#学习WPF笔记(一)
学习·c#·wpf
AOwhisky8 小时前
Redis 学习笔记(第三期):持久化与主从复制
运维·数据库·redis·笔记·学习·云计算
c238569 小时前
Linux C++ 进度条进阶美化与工程化封装
linux·运维·服务器
Tbisnic10 小时前
AI大模型学习第十一天:技术选型、安全防护与金融实战
python·学习·ai·大模型·提示词工程
xmtxz11 小时前
计算机网络基础课程学习心得:从理论抽象到硬核实战的进阶之路
运维·学习
凡人叶枫11 小时前
Effective C++ 条款17:以独立语句将 newed 对象置入智能指针
java·linux·开发语言·c++·算法