Hi3519v101gpio字符驱动-led设备树驱动dts

一、dts文件路径

1、arch/arm/boot/dts/hisi-hi3519v101.dtsi

2、arch/arm/boot/dts/hisi-hi3519v101-hmp-demb.dts

二、准备文件

1、led_dts_drv.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// 操作管脚为gpio3_2
// 管脚复用寄存器默认为gpio,这里就不去操作了
#define led_phy_base 0x12143000 //led管脚物理地址
#define led_phy_data 0x010		//led管脚数据偏移地址,0b00_0001_0000

#define gpio_phy_dir 0x400 //管脚方向寄存器偏移地址
#define gpio_out 0x4	   //gpio3_2 配置为输出,1输出 0输入def
#define gpio_out_h 0xFF
#define gpio_out_l 0x00

#define dts_led_name "dts_led"
#define dts_led_cnt 1

static void __iomem *led_base; //寄存器基地址
static void __iomem *led_dir;  //方向

// static struct class *leddrv_class;
// static struct device *leddrv_class_dev;
// int major;

//dts led 结构体
struct dts_led_dev
{
	dev_t devid;			//设备号
	struct cdev cdev;		//字符设备
	struct class *class;	//类
	struct device *device;  //设备
	int major;				//主设备号
	int minor;				//次设备号
	struct device_node *nd; //设备节点
};

struct dts_led_dev dts_led;

static int led_drv_open(struct inode *inode, struct file *filp)
{
	iowrite8(gpio_out, led_dir);
	printk("set gpio out mode\r\n");
	return 0;
}

static int led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	int val;

	__copy_from_user(&val, buf, count); //用户到内核,__copy_to_user();//内核到用户
	if (val == 1)
	{
		iowrite8(gpio_out_h, led_base);
		printk("set gpio out h\r\n");
	}
	else
	{
		iowrite8(gpio_out_l, led_base);
		printk("set gpio out l\r\n");
	}

	return 0;
}

static struct file_operations led_drv_fops =
	{
		.owner = THIS_MODULE, //这是一个宏,推向编译模块时自动创建的__this_module变量
		.open = led_drv_open,
		.write = led_drv_write,
};

int led_drv_init(void)
{
	struct property *property;
	int ret;
	const char *str;
	u32 regdata[2];

	//获取设备树中的属性信息
	//1、获取设备节点:
	dts_led.nd = of_find_node_by_path("/soc/amba/gpio_chip@12143000");
	if (dts_led.nd == NULL)
	{
		printk("gpio_chip@12143000 node nost find!\r\n");
		return -EINVAL;
	}
	else
	{
		printk("gpio_chip@12143000 node find!\r\n");
	}

	//2、获取compatible属性内容
	property = of_find_property(dts_led.nd, "compatible", NULL);
	if (property == NULL)
	{
		printk("compatible property find failed\r\n");
	}
	else
	{
		printk("compatible = %s\r\n", property->value);
	}

	//3、获取status属性内容
	ret = of_property_read_string(dts_led.nd, "status", &str);
	if (ret < 0)
	{
		printk("status read failed!\r\n");
	}
	else
	{
		printk("status = %s\r\n", str);
	}

	//4、获取reg属性内容
	ret = of_property_read_u32_array(dts_led.nd, "reg", regdata, 2);
	if (ret < 0)
	{
		printk("reg property read failed!\r\n");
	}
	else
	{
		u8 i = 0;
		printk("reg data:\r\n");
		for (i = 0; i < 2; i++)
			printk("%#X ", regdata[i]);
		printk("\r\n");
	}

	//地址映射:把物理地址转换为虚拟地址
	led_base = of_iomap(dts_led.nd, 0);
	led_dir = led_base + gpio_phy_dir;
	led_base = led_base + led_phy_data;

	// printk("led_base = 0x%x\n", (unsigned int)led_base);
	// printk("led_dir = 0x%x\n", (unsigned int)led_dir);

	//注册字符设备驱动
	//1、创建设备号
	if (dts_led.major)
	{
		dts_led.devid = MKDEV(dts_led.major, 0); //定义了设备号,直接创建
		register_chrdev_region(dts_led.devid, dts_led_cnt, dts_led_name);
	}
	else
	{																	   //未定义设备号
		alloc_chrdev_region(&dts_led.devid, 0, dts_led_cnt, dts_led_name); //没有定义先申请
		dts_led.major = MAJOR(dts_led.devid);							   //获取分配好的主设备号
		dts_led.minor = MINOR(dts_led.devid);							   //获取分配好的次设备号
	}
	printk("dts_led devid = %d\r\n", dts_led.devid);
	printk("dts_led major = %d, dts_led minor = %d\r\n", dts_led.major, dts_led.minor);
	//2、初始化cdev
	dts_led.cdev.owner = THIS_MODULE;
	cdev_init(&dts_led.cdev, &led_drv_fops);

	//3、添加一个cdev
	cdev_add(&dts_led.cdev, dts_led.devid, dts_led_cnt);

	//4、创建类
	dts_led.class = class_create(THIS_MODULE, dts_led_name);

	//5、创建设备
	dts_led.device = device_create(dts_led.class, NULL, dts_led.devid, NULL, dts_led_name); //dev/dts_led_name

	return 0;
}

void led_drv_exit(void)
{
	iounmap(led_base); //取消物理地址的映射

	cdev_del(&dts_led.cdev);							  //删除cdev
	unregister_chrdev_region(dts_led.devid, dts_led_cnt); // 注销设备号

	device_destroy(dts_led.class, dts_led.devid); //卸载设备
	class_destroy(dts_led.class);				  //卸载类
}

module_init(led_drv_init); //模块初始化接口
module_exit(led_drv_exit); //模块推出接口
MODULE_LICENSE("GPL");

2、test_led_dts_drv.c

#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
	int fd;
	int val=1;
 
	fd = open("/dev/dts_led", O_RDWR);	//打开设备
 
    if(fd < 0)
        printf("can`t open!\n");
	if(argc != 2)
	{
		printf("Usage :\n");
		printf("%s \n", argv[0]);
		return 0;
	}

	if (strcmp(argv[1], "on") == 0)
	{
		val  = 1;
	}
	else
	{
		val = 0;
	}
    write(fd, &val, 4);
	return 0;
}

3、测试

/ # insmod led_dts_drv.ko
gpio_chip@12143000 node find!
compatible = arm,pl061
status = okay
reg data:
0X12143000 0X1000
dts_led devid = 265289728
dts_led major = 253, dts_led minor = 0
/ #
/ # ./test_led_dts_drv on
set gpio out mode
set gpio out h
/ #
/ # ./test_led_dts_drv off
set gpio out mode
set gpio out l

/ # cat proc/devices
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 29 fb
 89 i2c
 90 mtd
128 ptm
136 pts
153 spi
180 usb
189 usb_device
204 ttyAMA
253 dts_led
254 bsg

 

你可能感兴趣的:(linux,gpio,驱动)