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

相关推荐
水云桐程序员6 小时前
从零开发软件的步骤,软件开发从零到完成应该怎么做?
笔记·学习·软件构建·个人开发
David猪大卫6 小时前
【Linux修炼】环境变量、进程地址空间
linux·c语言·经验分享·笔记·学习·ubuntu·centos
叼烟扛炮7 小时前
Linux 学习笔记(五十六):IO 多路复用初探——select 的“三宗罪”
linux·服务器·数据库·笔记·学习·php
Ruiery8 小时前
Linux 6.6内核内存管理深度解析(十五):CMA 连续内存分配器
linux·运维·服务器
测试界的小码农8 小时前
【Linux 命令实战(01):认识 Linux 终端,从零掌握第一个命令】
linux·运维·服务器
布裘9 小时前
【银河麒麟】重启后时区丢失?排查发现 localtime 被业务程序替换成硬链接
linux·运维·网络
GeW12 小时前
高端化转型进入“补底层”阶段:Linux与数据库的再定位
linux
silent12 小时前
龙芯3B6000M运行Yolov8+FastApi
linux·loongarch·loongnix·龙芯
西西弗Sisyphus13 小时前
理解 Linux 动态库加载:LD_LIBRARY_PATH
linux
AR-26710-13 小时前
Linux Day31——实操启停服务改端口重启
linux·运维