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

相关推荐
ltl28 分钟前
实时 OS 巡礼:VxWorks、QNX、Zephyr 与 PREEMPT_RT
linux
我是谁??36 分钟前
Ubuntu22.04更换清华源
linux·运维·服务器
知识分享小能手1 小时前
线性代数学习教程,从入门到精通,向量组的线性相关性 — 完整知识点梳理(7)
学习·线性代数·机器学习
Shell运维手记1 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
动词ing2 小时前
【学习笔记】C语言(数组指针与指针数组+字符数组+函数+参数传递+字符串作为形参+递归函数+指针函数+回调函数+结构体嵌套+内存动态分配函数)
c语言·笔记·学习
测试运维日常笔记3 小时前
Linux系统安装配置TigerVNC服务器完整指南
linux·运维·服务器
雾时之林4 小时前
Linux----cron定时服务
linux·运维·服务器
小O的算法实验室4 小时前
IEEE TII,学习为多目标深度学习生成偏好
人工智能·深度学习·学习
吃好睡好便好5 小时前
说说高温对情绪的影响
学习·生活·情绪·高温
wengqidaifeng5 小时前
1.从“会敲命令”到理解 Linux:15 个基础指令、文件树与命令执行的本质
linux·运维·服务器·ubuntu