完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1.时钟树
2.需要控制的LED的GPIO引脚 GPIO8_A1,找到对应的时钟控制描述 通过Adress maping 找到这个寄存器的地址:0xFF760000 + 0x0198 时钟使能:CRU_CLKGATE14_CON (0xFF760000 + 0x0198); IO复用: GRF_GPIO8A_IOMUX (0xFF770000 + 0x0080); IO方向: GPIO8_SWPORTA_DDR (0xFF7F0000 + 0x0004); IO数据: GPIO8_SWPORTA_DR (0xFF7F0000 + 0x0000,); 在rk3288_firefly.dts添加设备节点 myled-node { xxx_led = "led_for_test"; #address-cells = <1>; #size-cells = <1>; compatible = "rk3288_testled"; status = "okay"; reg = < 0xFF760198 4 /* 时钟使能*/ 0xFF770080 4 /* IO 复用*/ 0xFF7F0004 4 /* 设置方向*/ 0xFF7F0000 4>; /* 数据设置*/ }; 然后在内核根目录下 make dtbs,然后更换这个文件: /boot/rk3288-frefly.dtb #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DTSLED_CNT 1 /* 设备号个数 */ #define DTSLED_NAME "rk3288_dtsled" /* 名字 */ #define LEDOFF 0 /* 关灯 */ #define LEDON 1 /* 开灯 */ /* 设备结构体 */ struct dtsled_dev{ dev_t devid; /* 设备号 */ struct cdev cdev; /* cdev */ struct class *class; /* 类 */ struct device *device; /* 设备 */ int major; /* 主设备号 */ int minor; /* 次设备号 */ struct device_node *nd; /* 设备节点 */ }; struct dtsled_dev rk3288_dtsled; /* led设备 */ /* 映射后的寄存器虚拟地址指针 */ static void __iomem * CRU_CLKGATE14_CON; static void __iomem * GRF_GPIO8A_IOMUX ; static void __iomem * GPIO8A_SWPORTA_DDR; static void __iomem * GPIO8A_SWPORTA_DR ; void led_switch(u8 sta) { u32 val =0; if(sta == LEDON) { val = readl(GPIO8A_SWPORTA_DR); val &= ~(1<<1); writel(val,GPIO8A_SWPORTA_DR); //GPIO8_A1输出低电平 } else if(sta == LEDOFF) { val = readl(GPIO8A_SWPORTA_DR); val |= (1<<1); writel(val,GPIO8A_SWPORTA_DR); //GPIO8_A1输出高电平 } } /* * @description : 打开设备 * @param – inode : 传递给驱动的 inode * @param – filp : 设备文件,file 结构体有个叫做 private_data 的成员变量 * 一般在 open 的时候将 private_data 指向设备结构体。 * @return : 0 成功;其他 失败 */ static int led_open(struct inode *inode, struct file * filp) { filp->private_data = &rk3288_dtsled; //设置私有数据 return 0; } static ssize_t led_read(struct file *filp, char __user *buf,size_t cnt, loff_t *off_t) { return 0; } static ssize_t led_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *off_t) { int ret; unsigned char databuf[1]; unsigned char ledstat; ret = copy_from_user(databuf,buf,cnt); if(ret < 0) { printk("kernel write failed n"); return -1; } ledstat = databuf[0]; if(ledstat == LEDON) { led_switch(LEDON); } else if(ledstat == LEDOFF) { led_switch(LEDOFF); } return 0; } static int led_release(struct inode *inode, struct file *filp) { printk("led release n"); return 0; } static struct file_operations rk3288_dtsled_fops ={ .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, .release = led_release, }; /* * 驱动的入口函数 */ static int __init led_init(void) { int ret; const char *str; unsigned int regdata[14]; struct property *proper; unsigned int val =0; /* 获取设备树中的属性数据 */ //1.获取设备节点 rk3288_dtsled.nd = of_find_node_by_path("/myled-node"); if(rk3288_dtsled.nd == NULL) { printk("myled-node can not find n"); } else { printk("myled-node has been found n"); } //2.获取属性内容 proper = of_find_property(rk3288_dtsled.nd,"compatible",NULL); if(proper == NULL) { printk("compatible property find failed n"); } else { printk("compatible = %s n",(char *)proper->value); } /* 3、获取 status 属性内容 */ ret = of_property_read_string(rk3288_dtsled.nd, "status", &str); if(ret < 0){ printk("status read failed!rn"); } else { printk("status = %srn",str); } |
|
|
|
/* 4、获取 reg 属性内容 */
ret = of_property_read_u32_array(rk3288_dtsled.nd, "reg", regdata, 8); if(ret < 0) { printk("reg property read failed!rn"); } else { u8 i = 0; printk("reg data:rn"); for(i = 0; i < 8; i++) printk("%#X ", regdata); printk("rn"); } { struct platform_device *op = of_find_device_by_node(rk3288_dtsled.nd); printk("num_resources: %d n", op->num_resources); } #if 1 /* 1、寄存器地址映射 */ CRU_CLKGATE14_CON = ioremap(regdata[0], regdata[1]); GRF_GPIO8A_IOMUX = ioremap(regdata[2], regdata[3]); GPIO8A_SWPORTA_DDR = ioremap(regdata[4], regdata[5]); GPIO8A_SWPORTA_DR = ioremap(regdata[6], regdata[7]); #else /* 初始化LED */ CRU_CLKGATE14_CON = of_iomap(rk3288_dtsled.nd, 0); //GRF_GPIO8A_IOMUX = of_iomap(rk3288_dtsled.nd, 1); //GPIO8A_SWPORTA_DDR = of_iomap(rk3288_dtsled.nd, 2); //GPIO8A_SWPORTA_DR = of_iomap(rk3288_dtsled.nd, 3); #endif #if 1 //使能GPIO8的时钟 val = readl(CRU_CLKGATE14_CON); val &= ~(0<<8); val |= (1<<(8+16)); writel(val,CRU_CLKGATE14_CON); //设置GPIO8_A1的复用功能 val = readl(GRF_GPIO8A_IOMUX); val &= ~(0<<2); val |= (3<<(2+16)); writel(val,GRF_GPIO8A_IOMUX); //设置GPIO8_A1的方向输出 val = readl(GPIO8A_SWPORTA_DDR); val |= 1<<1; writel(val,GPIO8A_SWPORTA_DDR); //默认关闭led val = readl(GPIO8A_SWPORTA_DR); val |= (1<<1); writel(val,GPIO8A_SWPORTA_DR); #endif /* 注册字符设备驱动 */ //1.创建设备号 if(rk3288_dtsled.major){ rk3288_dtsled.devid = MKDEV(rk3288_dtsled.major,0); register_chrdev_region(rk3288_dtsled.devid,DTSLED_CNT,DTSLED_NAME); }else{ alloc_chrdev_region(&rk3288_dtsled.devid,0, DTSLED_CNT, DTSLED_NAME); //申请设备号 rk3288_dtsled.major = MAJOR(rk3288_dtsled.devid); rk3288_dtsled.minor = MINOR(rk3288_dtsled.devid); } printk("rk3288_dtsled major=%d,minor=%d n",rk3288_dtsled.major,rk3288_dtsled.minor); //初始化cdev rk3288_dtsled.cdev.owner = THIS_MODULE; cdev_init(&rk3288_dtsled.cdev,&rk3288_dtsled_fops); //添加一个cdev cdev_add(&rk3288_dtsled.cdev,rk3288_dtsled.devid,DTSLED_CNT); //创建类 rk3288_dtsled.class = class_create(THIS_MODULE,DTSLED_NAME); if(IS_ERR(rk3288_dtsled.class)) return PTR_ERR(rk3288_dtsled.class); //创建设备 rk3288_dtsled.device = device_create(rk3288_dtsled.class,NULL,rk3288_dtsled.devid, NULL,DTSLED_NAME); if(IS_ERR(rk3288_dtsled.device)){ return PTR_ERR(rk3288_dtsled.device); } return 0; } static void __exit led_exit(void) { iounmap(CRU_CLKGATE14_CON); iounmap(GRF_GPIO8A_IOMUX); iounmap(GPIO8A_SWPORTA_DDR); iounmap(GPIO8A_SWPORTA_DR); //注销字符设备驱动 cdev_del(&rk3288_dtsled.cdev); //删除cdev unregister_chrdev_region(rk3288_dtsled.devid,DTSLED_CNT); //注销设备号 device_destroy(rk3288_dtsled.class,rk3288_dtsled.devid); class_destroy(rk3288_dtsled.class); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); //这里of_iomap会报错:先留个坑,后面解决······································· #include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" #define LEDON 1 #define LEDOFF 0 int main(int argc, char *argv[]) { int fd,retvalue; char *filename; unsigned char databuf[1]; if(argc != 3) { printf("error usage n"); return -1; } filename = argv[1]; fd = open(filename,O_RDWR); if(fd < 0) { printf("file %s open failed n", filename); } databuf[0] = atoi(argv[2]); retvalue = write(fd,databuf,sizeof(databuf)); if(retvalue < 0) { printf("led write failed n"); close(fd); return -1; } retvalue = close(fd); printf("test nor n"); } Makefile文件 # 1. 使用不同的开发板内核时, 一定要修改KERN_DIR # 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量: # 2.1 ARCH, 比如: export ARCH=arm64 # 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu- # 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin # 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同, # 请参考各开发板的高级用户使用手册 KERN_DIR = /home/book/mysamba/RK_3288_SDK/linux-4.4 all: make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o ledtest ledtest.c clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order rm -f ledtest # 参考内核源码drivers/char/ipmi/Makefile # 要想把a.c, b.c编译成ab.ko, 可以这样指定: # ab-y := a.o b.o # obj-m += ab.o obj-m += rk3288_led_driver.o |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1906 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2382 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5175 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
浏览过的版块 |
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 05:07 , Processed in 0.756814 second(s), Total 73, Slave 56 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号