Rk3568驱动开发_点亮led灯(手动挡)_5

1.MMU简介

完成虚拟空间到物理空间的映射
内存保护设立存储器的访问权限,设置虚拟存储空间的缓冲特性

stm32点灯可以直接操作寄存器,但是linux点灯不能直接访问寄存器,linux会使能mmu

linux中操作的都是虚拟地址,要想访问物理地址0x0a就得先搞清楚0xa对应的虚拟地址

获得物理地址对应的虚拟地址使用ioremap函数,本质是个宏,参数分别是物理地址启始大小,要转换的字节数量

卸载驱动的时候用iounmap()卸载映射

stm32没有这个MMU其控制gpio直接操作寄存器就行,在linux上由于这个内存映射在,需要知道真实物理地址,反推其虚拟地址才能像stm32一样操作寄存器

linux做驱动有配置设备树更高级的操作方式,像这种操作寄存器的好似手动档

2.代码:

驱动:

c 复制代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define LED_MAJOR 200
#define LED_NAME "led"

#define PMU_GRF_BASE						      (0xFDC20000)
#define PMU_GRF_GPIO0C_IOMUX_L				(PMU_GRF_BASE + 0x0010)
#define PMU_GRF_GPIO0C_DS_0					  (PMU_GRF_BASE + 0X0090)
#define GPIO0_BASE						        (0xFDD60000)
#define GPIO0_SWPORT_DR_H				      (GPIO0_BASE + 0X0004)
#define GPIO0_SWPORT_DDR_H				    (GPIO0_BASE + 0X000C)

/* 映射后的寄存器虚拟地址指针 */
static void __iomem *PMU_GRF_GPIO0C_IOMUX_L_PI;
static void __iomem *PMU_GRF_GPIO0C_DS_0_PI;
static void __iomem *GPIO0_SWPORT_DR_H_PI;
static void __iomem *GPIO0_SWPORT_DDR_H_PI;

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

  return 0;
}

static int led_release(struct inode* inode, struct file* filp){

  return 0;
}

static ssize_t led_write(struct file* filp, const char __user* buf, size_t count, loff_t* ppos){

  return 0;
}

/* 字符设备操作集*/
static const struct file_operations led_fops = {
  .owner = THIS_MODULE,
  .write = led_write,
  .open = led_open,
  .release = led_release,
};

/*注册驱动加载卸载*/

static int __init led_init(void){ // 入口

  // 初始化led灯

  int ret = 0;
  u32 val = 0;

  PMU_GRF_GPIO0C_IOMUX_L_PI = ioremap(PMU_GRF_GPIO0C_IOMUX_L, 4);
	PMU_GRF_GPIO0C_DS_0_PI = ioremap(PMU_GRF_GPIO0C_DS_0, 4);
	GPIO0_SWPORT_DR_H_PI = ioremap(GPIO0_SWPORT_DR_H, 4);
	GPIO0_SWPORT_DDR_H_PI = ioremap(GPIO0_SWPORT_DDR_H, 4);
  // 初始化

  // 设置GPIO0_c0为GPIO功能
  val = readl(PMU_GRF_GPIO0C_IOMUX_L_PI);
  val &= ~(0x7 << 0); //最低三位置0
  val |= ((0x7 << 16) | (0x0 << 0)); // 16 17 18位置1其他不变,bit2:0:0,用作GPIO0_C0
  writel(val, PMU_GRF_GPIO0C_IOMUX_L_PI);

  // 设置GPIO_C0驱动能力为level5
  val = readl(PMU_GRF_GPIO0C_DS_0_PI);
  val &= ~(0x3f << 0);  // 0 ~ 5置0
  val |= ((0x3f << 16) | (0x3f << 0)); // 16 ~ 21置1,0~5置1同时用作GPIO0c0
  writel(val, PMU_GRF_GPIO0C_DS_0_PI);

  // 设置GPIOO0_c0为输出
  val = readl(GPIO0_SWPORT_DDR_H_PI);
  val &= ~(0x1 << 0); // 0置0
  val |= ((0x1 << 16) | (0x1 << 0)); // 16置1,0置1
  writel(val, GPIO0_SWPORT_DDR_H_PI);

  // 设置GPIO_c0为低电平,关闭LED
  val = readl(GPIO0_SWPORT_DR_H_PI);
  val &= ~(0x1 << 0);
  val |= ((0x1 << 16) | (0x0 << 0));
  writel(val, GPIO0_SWPORT_DR_H_PI);

  // 开灯

  val = readl(GPIO0_SWPORT_DR_H_PI);
  val &= ~(0X1 << 0); /* bit0 清零*/
  val |= ((0X1 << 16) | (0X1 << 0));	/* bit16 置1,允许写bit0,
                         bit0,高电平*/ 
  writel(val, GPIO0_SWPORT_DR_H_PI);  
  
  // 注册字符设备
  ret = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);

  if(ret < 0){
    printk("register chrdev failed!\r\n");
    return -EIO;
  }

  printk("led_init\r\n");
  return 0;
}

static void __exit led_exit(void){ // 出口

  u32 val = 0;

  // 关灯

  val = readl(GPIO0_SWPORT_DR_H_PI);
  val &= ~(0X1 << 0); /* bit0 清零*/
  val |= ((0X1 << 16) | (0X0 << 0));	/* bit16 置1,允许写bit0,
                         bit0,低电平	*/
  writel(val, GPIO0_SWPORT_DR_H_PI); 

  // 取消地址映射
  iounmap(PMU_GRF_GPIO0C_IOMUX_L_PI);
  iounmap(PMU_GRF_GPIO0C_DS_0_PI);
  iounmap(GPIO0_SWPORT_DR_H_PI);
  iounmap(GPIO0_SWPORT_DDR_H_PI);
  // 注销
  unregister_chrdev(LED_MAJOR, LED_NAME);
  printk("led_exit\r\n");

}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Narnat");

ioremap(PMU_GRF_GPIO0C_IOMUX_L, 4);将物理地址转虚拟内存

在程序挂载时初始化一些寄存器,并点亮led灯,卸载时关闭led灯

3.现象:


相关推荐
sukalot14 小时前
window显示驱动开发—视频呈现网络简介
驱动开发
sukalot1 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(二)
驱动开发
zwhSunday1 天前
Linux驱动开发(1)概念、环境与代码框架
linux·运维·驱动开发
sukalot2 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(三)
驱动开发
sukalot2 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(一)
驱动开发
cxr8283 天前
基于Claude Code的 规范驱动开发(SDD)指南
人工智能·hive·驱动开发·敏捷流程·智能体
zwhSunday3 天前
Linux驱动开发(2)进一步理解驱动
linux·驱动开发
被遗忘的旋律.3 天前
Linux驱动开发笔记(十)——中断
linux·驱动开发·笔记
路溪非溪4 天前
Linux驱动如何向应用层提供sysfs操作接口
linux·arm开发·驱动开发
sukalot4 天前
window显示驱动开发—监视筛选器驱动程序(三)
驱动开发