对应自己的实验目录:5-dts-led
略
int register_chrdev_region(dev_t from, unsigned count, const char *name)
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
struct class *class_create(owner, name) //宏定义
struct device *device_create(struct class *class, struct device *parent, \
dev_t devt, void *drvdata, const char *fmt, ...)
static inline struct device_node *of_find_node_by_path(const char *path)
int of_property_count_elems_of_size(const struct device_node *np, \
const char *propname, int elem_size)
int of_property_read_u32_array(const struct device_node *np, \
const char *propname, u32 *out_values, \
size_t sz)
void __iomem*ioremap(cookie,size) // 宏定义
void iounmap(volatile void __iomem *addr) // 宏定义
static __always_inline void *kmalloc(size_t size, gfp_t flags)
static void kfree(void *where) // 宏定义
void device_destroy(struct class *class, dev_t devt)
extern void class_destroy(struct class *cls)
void cdev_del(struct cdev *p)
void unregister_chrdev_region(dev_t from, unsigned count)
在设备树的根节点下面创建一个节点,在reg属性里编写需要的寄存器地址和长度。
/ {
alphaled {
compatible = "alphaled";
#address-cells = <1>;
#size-cells = <1>;
status = "okay";
reg = < 0X020C406C 0X04 /* CCM_CCGR1_BASE */
0X020E0068 0X04 /* SW_MUX_GPIO1_IO03_BASE */
0X020E02F4 0X04 /* SW_PAD_GPIO1_IO03_BASE */
0X0209C000 0X04 /* GPIO1_DR_BASE */
0X0209C004 0X04 /* GPIO1_GDIR_BASE */
>;
};
};
2.1 驱动源文件
#include "include.h"
#define LEDDTS_NAME "led"
#define LEDDTS_NUM 1
struct 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;
else
val &=~ (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>