5、设备树操作reg
生活随笔
收集整理的這篇文章主要介紹了
5、设备树操作reg
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
對應自己的實驗目錄:5-dts-led
一、需要注意的地方
略
二、涉及的函數的用法介紹
1.注冊設備號
int register_chrdev_region(dev_t from, unsigned count, const char *name)- @from: 申請的設備號
- @count: 需要申請的設備數量
- @name: 設備的名稱
- Return:0,成功 <0,失敗
2.申請設備號
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)- @dev: 被申請的設備號指針
- @baseminor: 需要申請的第一個子設備號
- @count: 需要申請的設備數量
- @name: 設備的名稱
- Return:0,成功 <0,失敗
3.初始化和注冊字符設備
void cdev_init(struct cdev *cdev, const struct file_operations *fops)- @cdev: 字符設備結構體指針
- @fops: file_operations結構體指針
- @p: 字符設備結構體指針
- @dev: 設備號
- @count: 連續的副設備號數量(設備的數量)
- Return: <0,失敗
4.創建類和設備(掛載設備節點)
struct class *class_create(owner, name) //宏定義- @owner: 寫THIS_MODULE
- @name: 節點名稱
- Returns: 通過 IS_ERR() 檢查錯誤,PTR_ERR() 顯示錯誤
- @class: 指向類的指針
- @parent: 指向父設備結構體(目前的只寫NULL)
- @devt: 設備號
- @drvdata: (目前的只寫NULL)
- @fmt: 設備名
- Returns: 通過 IS_ERR() 檢查錯誤,PTR_ERR() 顯示錯誤
5.獲取設備節點
static inline struct device_node *of_find_node_by_path(const char *path)- @path: 節點在設備樹里的路徑
- Returns: NULL,失敗
6.獲取屬性的元素個數
int of_property_count_elems_of_size(const struct device_node *np, \const char *propname, int elem_size)- @np: 設備樹節點指針
- @propname: 屬性名
- @elem_size: 單個元素的大小
- Returns: >0,成功;<0,失敗
??-EINVAL 屬性不存在或長度不匹配、 -ENODATA 沒有值
7.從屬性中獲取32位整數數組(寄存器組的地址和長度)
int of_property_read_u32_array(const struct device_node *np, \const char *propname, u32 *out_values, \size_t sz)- @np: 設備樹節點指針
- @propname: 屬性名
- @out_values: 數組的指針
- @sz: 需要讀取的數組個數
- Returns: 0,成功;<0,失敗
??-EINVAL 屬性不存在、-ENODATA 屬性沒值、 -EOVERFLOW屬性長度不夠
8.寄存器地址映射
void __iomem*ioremap(cookie,size) // 宏定義- @cookie: 寄存器地址
- @size: 寄存大小
9.寄存器取消映射
void iounmap(volatile void __iomem *addr) // 宏定義- @addr: 取消映射的虛擬地址
10.內存申請
static __always_inline void *kmalloc(size_t size, gfp_t flags)- @size: 申請內存的大小
- @flags: 申請的內存類型 (一般是:GFP_KERNEL) ;詳情:文件slab.h 行365
11.內存釋放
static void kfree(void *where) // 宏定義- @where: 需要釋放的內存地址
12.銷毀設備
void device_destroy(struct class *class, dev_t devt)- @class: 類的指針
- @devt: 設備號
13.銷毀類
extern void class_destroy(struct class *cls)- @cls: 類的指針
14.銷毀字符設備
void cdev_del(struct cdev *p)- @p: 字符設備結構體的指針
15.釋放設備號
void unregister_chrdev_region(dev_t from, unsigned count)- @from: 設備號
- @count: 設備的數量
三、編寫過程
1、編寫設備樹節點
在設備樹的根節點下面創建一個節點,在reg屬性里編寫需要的寄存器地址和長度。
2、驅動代碼
2.1 驅動源文件
#include "include.h"#define LEDDTS_NAME "led" #define LEDDTS_NUM 1struct Leddts_dev {dev_t devid;struct cdev cdev;struct class *class;struct device *device;int major;int minor;struct device_node *dev_node;int reg_num;u32 *reg_value; };static unsigned int* va_ccm_ccgr1 = NULL; // static void __iomem* static unsigned int* va_mux_gpio1_io03 = NULL; // static void __iomem* static unsigned int* va_pad_gpio1_io03 = NULL; // static void __iomem* static unsigned int* va_gpio1_dr = NULL; // static void __iomem* static unsigned int* va_gpio1_gdir = NULL; // static void __iomem*struct Leddts_dev leddts_dev;int leddts_open (struct inode *inode, struct file *filep) {unsigned int val;/* 打開時鐘 */val = readl(va_ccm_ccgr1);val |= 0x0c000000;writel(val, va_ccm_ccgr1);/* 設置復用 */val = readl(va_mux_gpio1_io03);val = 0x05;writel(val, va_mux_gpio1_io03);/* 設置電氣屬性 */val = readl(va_pad_gpio1_io03);val = 0x190a1;writel(val, va_pad_gpio1_io03);/* 設置方向 */val = readl(va_gpio1_gdir);val |= 1<<3;writel(val, va_gpio1_gdir);return 0; } int leddts_release (struct inode *inode, struct file *filep) {return 0; } ssize_t leddts_read (struct file *filep, char __user *buf, size_t cnt, loff_t *offt) {return 0; } ssize_t leddts_write (struct file *filep, const char __user *buf, size_t cnt, loff_t *offt) {int ret;unsigned int val;char data;ret = copy_from_user(&data, buf, 1);if(ret < 0) {return 0;}/* 設置電平 */val = readl(va_gpio1_dr);if(data == 1)val |= 1<<3;elseval &=~ (1<<3);writel(val, va_gpio1_dr);return 1; }struct file_operations fops = {.owner = THIS_MODULE,.open = leddts_open,.read = leddts_read,.write = leddts_write,.release = leddts_release };/*** @brief 驅動入口* */ static int __init leddts_init(void) {int ret = 0;int i;/* 申請一個空閑設備號 */leddts_dev.major = 0;if(leddts_dev.major) {leddts_dev.devid = MKDEV(leddts_dev.major, 0);ret = register_chrdev_region(leddts_dev.devid, LEDDTS_NUM, LEDDTS_NAME);} else {ret = alloc_chrdev_region(&leddts_dev.devid, 0, LEDDTS_NUM, LEDDTS_NAME);leddts_dev.major = MAJOR(leddts_dev.devid);leddts_dev.minor = MINOR(leddts_dev.devid);}if(ret) {ret = -EINVAL;goto fail_regi_chrdev;}/* 注冊設備 */leddts_dev.cdev.owner = THIS_MODULE;cdev_init(&leddts_dev.cdev, &fops);ret = cdev_add(&leddts_dev.cdev, leddts_dev.devid, LEDDTS_NUM);if(ret < 0) {goto fail_cdev_add;}/* 掛載設備節點 */leddts_dev.class = class_create(THIS_MODULE, LEDDTS_NAME);if (IS_ERR(leddts_dev.class)) {ret = PTR_ERR(leddts_dev.class);goto fail_class_create;}leddts_dev.device = device_create(leddts_dev.class, NULL, leddts_dev.devid, NULL, LEDDTS_NAME);if (IS_ERR(leddts_dev.device)) {ret = PTR_ERR(leddts_dev.class);goto fail_device_create;}/* 1、獲取節點 */leddts_dev.dev_node = of_find_node_by_path("/alphaled");if(leddts_dev.dev_node == NULL) {ret = -EINVAL;goto fail_find_node;}/* 2、讀取數字屬性的數組 */leddts_dev.reg_num = of_property_count_elems_of_size(leddts_dev.dev_node, "reg", sizeof(u32));if(leddts_dev.reg_num < 0) {ret = -EINVAL;goto fail_property_elems_size;}leddts_dev.reg_value = (u32*)kmalloc(sizeof(u32)*leddts_dev.reg_num, GFP_KERNEL);ret = of_property_read_u32_array(leddts_dev.dev_node, "reg", leddts_dev.reg_value, leddts_dev.reg_num);if(ret != 0) {goto fail_read_u32_property;}/* 打印屬性值 */for(i=0; i<leddts_dev.reg_num; i+=2) {printk("reg = %x %x \r\n", leddts_dev.reg_value[i], leddts_dev.reg_value[i+1]);}/* 寄存器映射 */va_ccm_ccgr1 = ioremap(leddts_dev.reg_value[0], leddts_dev.reg_value[1]);va_mux_gpio1_io03 = ioremap(leddts_dev.reg_value[2], leddts_dev.reg_value[3]);va_pad_gpio1_io03 = ioremap(leddts_dev.reg_value[4], leddts_dev.reg_value[5]);va_gpio1_dr = ioremap(leddts_dev.reg_value[6], leddts_dev.reg_value[7]);va_gpio1_gdir = ioremap(leddts_dev.reg_value[8], leddts_dev.reg_value[9]);return 0;fail_read_u32_property:kfree(leddts_dev.reg_value); fail_property_elems_size: fail_find_node:device_destroy(leddts_dev.class, leddts_dev.devid); fail_device_create:class_destroy(leddts_dev.class); fail_class_create:cdev_del(&leddts_dev.cdev); fail_cdev_add:unregister_chrdev_region(leddts_dev.devid, LEDDTS_NUM); fail_regi_chrdev:return ret; }/*** @brief 驅動出口* */ static void __exit leddts_exit(void) {iounmap(va_ccm_ccgr1);iounmap(va_mux_gpio1_io03);iounmap(va_pad_gpio1_io03);iounmap(va_gpio1_dr);iounmap(va_gpio1_gdir);kfree(leddts_dev.reg_value);device_destroy(leddts_dev.class, leddts_dev.devid);class_destroy(leddts_dev.class);cdev_del(&leddts_dev.cdev);unregister_chrdev_region(leddts_dev.devid, LEDDTS_NUM); }module_init(leddts_init); module_exit(leddts_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("ls");2.2需要的頭文件
#include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/io.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h>總結
以上是生活随笔為你收集整理的5、设备树操作reg的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 混沌理论(转载)
- 下一篇: 干货 | PCB多层板为什么都是偶数层?