首页 > 其他分享 >泰山派学习13--设备树LED字符驱动

泰山派学习13--设备树LED字符驱动

时间:2024-07-14 14:19:25浏览次数:16  
标签:va 13 LED val -- ALERT KERN int dtsled

1、在泰山派设备树的/根节点上添加zbl_led子节点(路径:Z:\sdk\linux\kernel\arch\arm64\boot\dts\rockchip)

  打开tspi-rk3566-user-v10-linux.dts设备树源文件

       

  在根目录下添加zbl_led子节点

       

2、在SDK上编译kernel(./build.sh kernel)

  执行内核编译:./build.sh kernel

       

  内核编译成功输出:

       

  查看boot.img是否生成最新的

       

 

3、烧录boot.img镜像(前提已经烧录了buildroot的uboot,且正常运行的)

  仅勾选boot.img,进行烧录

      

4、查看设备树上节点是否添加成功(cd /proc/device-tree)

  ls 

  cd zbl_led

  ls 

      

   查看对应的属性是否与设置的一致

  cat status

      

 5、编写设备树的字符驱动对应函数

/*
** dtsled.c
** 复用型引脚分为5组(GPIO0~4),每组里面都有32个复用型引脚,而且又分为4个小组(A、B、C、D),每个小组8个引脚(0~7)
** GPIO3_4B
** 在GPIO3大组,第二的B小组,第4个引脚,
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>


//设备名称
#define DEV_NAME "dtsled"
#define DEV_CNT 1
//复用功能寄存器
//#define PMU_GRF_GPIO3B_IOMUX_H 0xFDC6004C
//GPIO方向控制寄存器
//#define GPIO_SWPORT_DDR_L 0xFE760008
//GPIO数据寄存器
//#define GPIO_SWPORT_DR_L 0xFE760000


#define LED_ON 1
#define LED_OFF 0

char kbuf[128] = {0};


//定义新的一个结构体 struct chr_dev
struct dtsled_dev{
dev_t dev_id; //设备编号
struct cdev cdev; //内核字符设备
struct class *class; //设备类
struct device *device; //设备
int major; //主设备
int minor; //从设备
struct device_node *nd; //设备节点
unsigned int __iomem *va_iomux; //地址映射虚拟地址指针
unsigned int __iomem *va_ddr;
unsigned int __iomem *va_dr;
};

static struct dtsled_dev dtsled;

 

void led_switch(unsigned char state)
{
unsigned int val;

if(state == LED_ON){
val = ioread32(dtsled.va_dr);
val |= ((unsigned int)0x01 << (12+16));
val |= ((unsigned int)0x01 << (12)); //输出高电平
iowrite32(val, dtsled.va_dr);
printk(KERN_ALERT "[ KERN_ALERT ] led turn on dr_val=%#lX.\n", *(dtsled.va_dr));
}
else if(state == LED_OFF){
val = ioread32(dtsled.va_dr);
val |= ((unsigned int)0x01 << (12+16));
val &= ~((unsigned int)0x01 << (12)); //输出低电平
iowrite32(val, dtsled.va_dr);
printk(KERN_ALERT "[ KERN_ALERT ] led turn off dr_val=%#lX.\n", *(dtsled.va_dr));
}
}


void led_unmap(void)
{

iounmap(dtsled.va_dr);
iounmap(dtsled.va_ddr);
iounmap(dtsled.va_iomux);


}


int led_open(struct inode *inode, struct file *file)
{

//把文件的私有数据 private_data 指向设备结构体 dtsled
file->private_data = &dtsled;

printk(KERN_ALERT "[ KERN_ALERT ] dtsled open ...\n");

return 0;
}

ssize_t led_read(struct file *file, char __user *ubuf, size_t size, loff_t *offset)
{
printk(KERN_ALERT "[ KERN_ALERT ] dtsled read!\n");
return 0;
}

ssize_t led_write(struct file *file, const char __user *ubuf, size_t size, loff_t *offset)
{
unsigned char ret;

if(size > sizeof(kbuf)){
size = sizeof(kbuf);

}
if(copy_from_user(kbuf, ubuf, size)){
printk(KERN_ALERT "[ KERN_ALERT ] copy data form user fail!\n");
return -EIO;
}

ret = kbuf[0];

if(ret == LED_ON){
led_switch(LED_ON);
}
else if(ret == LED_OFF){
led_switch(LED_OFF);
}

printk(KERN_ALERT "[ KERN_ALERT ] dtsled write!\n");
return size;

}

int led_close(struct inode *inode, struct file *file)
{
printk(KERN_ALERT "[ KERN_ALERT ] dtsled close!\n");
return 0;
}

struct file_operations dtsled_fops= {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_close
};


static int __init ledcdev_init(void)
{
unsigned char i = 0;
unsigned int val = 0;
int ret = 0;
unsigned int regdata[12];
const char *str;
struct property *proper;


//读取设备树节点的属性数据
//获取设备节点:zbl_led
dtsled.nd = of_find_node_by_path("/zbl_led");
if(dtsled.nd == NULL){
printk(KERN_ALERT "[ KERN_ALERT ] zbl_led node find failed.\n");
goto fail_find_node;
}else{
printk(KERN_ALERT "[ KERN_ALERT ] zbl_led node find ok.\n");
}

//获取设备的compatible属性内容
proper = of_find_property(dtsled.nd, "compatible", NULL);
if(proper == NULL){
printk(KERN_ALERT "[ KERN_ALERT ] compatible property find failed.\n");
}else{
printk(KERN_ALERT "[ KERN_ALERT ] compatible property find ok.\n");
}

//获取 status 属性内容
ret = of_property_read_string(dtsled.nd, "status", &str);
if(ret < 0){
printk(KERN_ALERT "[ KERN_ALERT ] status read failed!\n");

}else{
printk(KERN_ALERT "[ KERN_ALERT ] status = %s\n",str);
}

//获取设备的reg属性内容
ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 12);
if(ret < 0 ){
printk(KERN_ALERT "[ KERN_ALERT ] reg property find failed.\n");
}else{
printk(KERN_ALERT "[ KERN_ALERT ] regdata:\n");
for(i=0; i<12; i++){
printk(KERN_ALERT "[ KERN_ALERT ] %#X ", regdata[i]);
}
printk(KERN_ALERT "[ KERN_ALERT ] reg property find ok.\n");
}



//物理地址映射虚拟地址,32位==>A0~A7 B0~B7 C0~C7 D0~D7,其中A B对应低16位,C D对应高16位
dtsled.va_iomux = of_iomap(dtsled.nd, 0);
dtsled.va_ddr = of_iomap(dtsled.nd, 1);
dtsled.va_dr = of_iomap(dtsled.nd, 2);

//设置IO复用
val = ioread32(dtsled.va_iomux);
//val |= 0x70000;
val |= ((unsigned int)0x07 << (0+16));
val &= ~((unsigned int)0x01 << (0));
iowrite32(val, dtsled.va_iomux);
printk(KERN_ALERT "[ KERN_ALERT ] va_iomux_val=%#lX.\n", *(dtsled.va_iomux));

//设置输出模式
val = ioread32(dtsled.va_ddr);
val = ((unsigned int)0x01 << (12+16));
val |= ((unsigned int)0x01 << (12));
iowrite32(val, dtsled.va_ddr);
printk(KERN_ALERT "[ KERN_ALERT ] va_ddr_val=%#lX.\n", *(dtsled.va_ddr));

//输出低电平
val = ioread32(dtsled.va_dr);
val |= ((unsigned int)0x01 << (12+16));
val &= ~((unsigned int)0x01 << (12));
iowrite32(val, dtsled.va_dr);
printk(KERN_ALERT "[ KERN_ALERT ] va_dr_val=%#lX.\n", *(dtsled.va_dr));

//注册字符设备驱动
//创建设备号
if(dtsled.major){
dtsled.dev_id = MKDEV(dtsled.major, 0);
ret = register_chrdev_region(dtsled.dev_id, DEV_CNT, DEV_NAME);
if(ret < 0){
printk(KERN_ALERT "[ KERN_ALERT ] can't regsiter %s char driver [ret=%d]\n", DEV_CNT, DEV_NAME);
goto fail_devid;
}
}else{
ret = alloc_chrdev_region(&dtsled.dev_id, 0, DEV_CNT, DEV_NAME);
if(ret < 0){
printk(KERN_ALERT "[ KERN_ALERT ] %s can't alloc chrdev region, ret=%d.\n", DEV_NAME, ret);
goto fail_devid;
}
dtsled.major = MAJOR(dtsled.dev_id);
dtsled.minor = MINOR(dtsled.dev_id);
}

printk(KERN_ALERT "[ KERN_ALERT ] dtsled major=%d, minor=%d.\n", dtsled.major, dtsled.minor);

//关联结构体
dtsled.cdev.owner = THIS_MODULE;
cdev_init(&dtsled.cdev, &dtsled_fops);

ret = cdev_add(&dtsled.cdev, dtsled.dev_id, DEV_CNT);
if(ret < 0){
goto del_unregister;
}

dtsled.class = class_create(THIS_MODULE, DEV_NAME);
if(IS_ERR(dtsled.class)){
goto del_cdev;
}


dtsled.device = device_create(dtsled.class, NULL, dtsled.dev_id, NULL, DEV_NAME);
if(IS_ERR(dtsled.device)){
goto destroy_class;
}


printk(KERN_ALERT "[ KERN_ALERT ] dtsled init ...\n");
return 0;

destroy_class:
class_destroy(dtsled.class);
del_cdev:
cdev_del(&dtsled.cdev);
del_unregister:
unregister_chrdev_region(dtsled.dev_id, DEV_CNT);
fail_devid:
led_unmap();
fail_find_node:
return -EIO;

}


static void __exit ledcdev_exit(void)
{

printk(KERN_ALERT "[ KERN_ALERT ] dtsled exit ...\n");

led_unmap();

cdev_del(&dtsled.cdev);

unregister_chrdev_region(dtsled.dev_id, DEV_CNT);

device_destroy(dtsled.class, dtsled.dev_id);

class_destroy(dtsled.class);

}

module_init(ledcdev_init);

module_exit(ledcdev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("zbl");

 

6、编写应用函数

/*
** dtsledapp.c
**
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>


#define LED_ON 1
#define LED_OFF 0


int main(int argc, char *argv[])
{

int fd;
int ret;
unsigned char databuf[1] = {0};

if(argc != 2){
printf("Error Usage!\n");
return -1;
}

fd = open("/dev/dtsled", O_RDWR);
if(fd == -1)
{
printf("open %s failed.\n", "/dev/dtsled");
return -1;
}

databuf[0] = atoi(argv[1]);
ret = write(fd, databuf, sizeof(databuf));
if(ret < 0){
printf("LED control failed.\n");
close(fd);
return -1;
}

ret = close(fd);
if(ret < 0){
printf("close %s failed.\n", "/dev/dtsled");
return -1;
}

return 0;
}

7、编写makefile (修改对应文件名称)

      

8、拷贝到开发板(adb push xxx xxx),并对文件进行赋权(chmod 777 app dtsled.ko)

     

9、执行测试验证

  查看现有内核模块(lsmod), 并加载LED模块(insmod dtsled.ko)

      

   查看设备驱动(cat  /proc/devices)

      

  查看文件属性

      

  执行应用程序进行LED测试

       

   卸载驱动模块

        

 

标签:va,13,LED,val,--,ALERT,KERN,int,dtsled
From: https://www.cnblogs.com/zblblog/p/18301256

相关文章

  • 【转载】【内存】为什么手工drop_caches之后cache值并未减少?
    在Linux系统上查看内存使用状况最常用的命令是"free",其中buffers和cache通常被认为是可以回收的:$freetotalusedfreesharedbufferscachedMem:3276471610675483169716815833212593096-/+buffers/cache:47444032290276Swap:21......
  • 死锁案例
    1publicpartialclassForm1:Form2{3publicForm1()4{5InitializeComponent();6}78privatevoidForm1_Load(objectsender,EventArgse)9{1011}1213private......
  • 题解:CodeForces 618C Constellation[贪心/模拟]
    CodeForces618CC.Constellationtimelimitpertest:2secondsmemorylimitpertest:256megabytesinputstandardinputoutputstandardoutputCatNokuhasobtainedamapofthenightsky.Onthismap,hefoundaconstellationwithnstarsnumberedfrom......
  • BT面板去除商业推广信息
    宝塔在7.8版本加入了强制绑定账户,页面元素的限制倒也还好,很简单就能去除,可问题是软件商店的接口加入了登录校验,没登录的情况下获取不到软件列表自然也就无法安装软件了,长远看来用户绑定是必不可少了。当时只是一个强制绑定问题,可万万没想到升级到7.9版本后,首页加入了广告:对专......
  • mongodb数据库
    mongodb与mysql区别:mysql(关系型数据库):优点:支持事务:对于需要保证数据一致性和完整性的操作,事务处理能力非常重要数据一致性:严格遵守关系数据的特征ACID(原子性,一致性,隔离性,持久性)复杂查询优化:对于复杂的关联查询和数据分析,具有较好的优化器和性能场景:如果数据有明确的结......
  • Camstar Portal cs中实现打开打开其它VP页面并将打开的VP最大窗口显示
    1.在主要功能VP页面中新增两个变量(DataContractMembers) 2.在需要跳转到新的VP页面中添加两个变量来接受主页面传过来的数据 3.在功能主界面绑定的CS中添加对应的跳转逻辑,与传值逻  4.要实现跳转页面的最大化显示,需要在跳转页面的绑定CS中的Onloa函数中添加一段下面的......
  • 题解:CodeForces 835 D Palindromic characteristics[区间dp/马拉车Manacher]
    CodeForces835DD.Palindromiccharacteristicstimelimitpertest:3secondsmemorylimitpertest:256megabytes*inputstandardinputoutputstandardoutputPalindromiccharacteristicsofstring\(s\)withlength\(|s|\)isasequenceof\(|s|\)in......
  • PMP-项目运行环境
     影响项目环境有两大客观因素和人,两大客观因素:事业环境因素和组织过程资产。事业环境因素包括组织外部因素和组织内部因素,组织内部因素是组织可以改变的,但是项目不能我改变;在默认条件下事业环境因素是项目无法改变的。事业环境因素是指项目团队不能控制的,将对项目产生影响、......
  • LivePortrait 数字人:开源的图生视频模型,本地部署和专业视频制作详细教程
    看到上面面部表情动态图片,是不是感觉挺有有意思?它就是通过快手、中科大和复旦大学联合研发的图生视频开源大模型LivePortrait(灵动人像)生成的视频。通过LivePortrait大模型,我们只需要一张人脸正面图片和一段文字或音频,即可制作专业的视频内容,例如产品介绍、教学课程、趣味视频等......
  • 题解:CodeForces 1019 A Elections[贪心/三分]
    CodeForces1019AA.Electionstimelimitpertest:2secondsmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputAsyouknow,majorityofstudentsandteachersofSummerInformaticsSchoolliveinBerlandforthemostparto......