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

相关推荐
0vvv017 小时前
删除wsl环境下的Ubuntu系统
linux·运维·ubuntu
@土豆17 小时前
Ubuntu 22.04 运行 Filebeat 7.11.2 崩溃问题分析及解决文档
linux·数据库·ubuntu
头疼的程序员17 小时前
计算机网络:自顶向下方法(第七版)第八章 学习分享(三)
网络·学习·计算机网络
C++ 老炮儿的技术栈17 小时前
GCC编译时无法向/tmp 目录写入临时汇编文件,因为设备空间不足,解决
linux·运维·开发语言·汇编·c++·git·qt
_李小白18 小时前
【OSG学习笔记】Day 37: NodeVisitor(顶点访问器)
笔记·学习
爱莉希雅&&&18 小时前
linux中MySQL数据库备份恢复的四种方法(更新中)
linux·数据库·mysql·数据库备份·mysqldumper
coppher18 小时前
Ubuntu 22.04 amd64 离线安装 Docker 完整教程
linux·docker
程序员雷欧18 小时前
大模型应用开发学习第八天
大数据·人工智能·学习
xyz59918 小时前
如何在 WSL 中删除指定版本的 Ubuntu 以及安装
linux·运维·ubuntu
晓晓hh18 小时前
JavaSE学习——set集合和Map映射
学习