1125 views|1 replies

410

Posts

3

Resources
The OP
 

okmx6q -- platform mode LED driver test [Copy link]

Platform mode LED driver test.

1. Driver

1.1、leddevice.c

#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/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

/* 
 * 寄存器地址定义
 */
#define IOMUXC_SW_MUX_CTL_PAD_EIM_ADDR17_BASE 	(0X020E00F0)
#define IOMUXC_SW_PAD_CTL_PAD_EIM_ADDR17_BASE 	(0X020E0404)
#define GPIO2_DR_BASE							(0X020A0000)
#define GPIO2_GDIR_BASE							(0X020A0004)
#define REGISTER_LENGTH				4

/* [url=home.php?mod=space&uid=1068364]@description[/url] : 释放flatform设备模块的时候此函数会执行	
 * @param - dev 	: 要释放的设备 
 * [url=home.php?mod=space&uid=784970]@return[/url] : 无
 */
static void	led_release(struct device *dev)
{
	printk("led device released!\r\n");	
}

/*  
 * 设备资源信息,也就是LED0所使用的所有寄存器
 */
static struct resource led_resources[] = {
	[0] = {
		.start	= IOMUXC_SW_MUX_CTL_PAD_EIM_ADDR17_BASE,
		.end	= (IOMUXC_SW_MUX_CTL_PAD_EIM_ADDR17_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= IOMUXC_SW_PAD_CTL_PAD_EIM_ADDR17_BASE,
		.end	= (IOMUXC_SW_PAD_CTL_PAD_EIM_ADDR17_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[2] = {
		.start	= GPIO2_DR_BASE,
		.end	= (GPIO2_DR_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[3] = {
		.start	= GPIO2_GDIR_BASE,
		.end	= (GPIO2_GDIR_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
};


/*
 * platform设备结构体 
 */
static struct platform_device leddevice = {
	.name = "imx6q-led",
	.id = -1,
	.dev = {
		.release = &led_release,
	},
	.num_resources = ARRAY_SIZE(led_resources),
	.resource = led_resources,
};
		
/*
 * @description	: 设备模块加载 
 * @param 		: 无
 * @return 		: 无
 */
static int __init leddevice_init(void)
{
	return platform_device_register(&leddevice);
}

/*
 * @description	: 设备模块注销
 * @param 		: 无
 * @return 		: 无
 */
static void __exit leddevice_exit(void)
{
	platform_device_unregister(&leddevice);
}

module_init(leddevice_init);
module_exit(leddevice_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZZK");





1.2、leddriver.c

#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/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define LEDDEV_CNT		1			/* 设备号长度 	*/
#define LEDDEV_NAME		"platled"	/* 设备名字 	*/
#define LEDOFF 			0
#define LEDON 			1

/* 寄存器名 */
static void __iomem *SW_MUX_GPIO2_IO21;
static void __iomem *SW_PAD_GPIO2_IO21;
static void __iomem *GPIO2_DR;
static void __iomem *GPIO2_GDIR;

/* leddev设备结构体 */
struct leddev_dev{
	dev_t devid;			/* 设备号	*/
	struct cdev cdev;		/* cdev		*/
	struct class *class;	/* 类 		*/
	struct device *device;	/* 设备		*/
	int major;				/* 主设备号	*/		
};

struct leddev_dev leddev; 	/* led设备 */

/*
 * @description		: LED打开/关闭
 * @param - sta 	: LEDON(0) 打开LED,LEDOFF(1) 关闭LED
 * @return 			: 无
 */
void led0_switch(u8 sta)
{
	u32 val = 0;
	if(sta == LEDON){
		val = readl(GPIO2_DR);
		val &= ~(1 << 21);	
		writel(val, GPIO2_DR);
	}else if(sta == LEDOFF){
		val = readl(GPIO2_DR);
		val|= (1 << 21);	
		writel(val, GPIO2_DR);
	}	
}

/*
 * @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 = &leddev; /* 设置私有数据  */
	return 0;
}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	int retvalue;
	unsigned char databuf[1];
	unsigned char ledstat;

	retvalue = copy_from_user(databuf, buf, cnt);
	if(retvalue < 0) {
		return -EFAULT;
	}

	ledstat = databuf[0];		/* 获取状态值 */
	if(ledstat == LEDON) {
		led0_switch(LEDON);		/* 打开LED灯 */
	}else if(ledstat == LEDOFF) {
		led0_switch(LEDOFF);	/* 关闭LED灯 */
	}
	return 0;
}

/* 设备操作函数 */
static struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.write = led_write,
};

/*
 * @description		: flatform驱动的probe函数,当驱动与
 * 					  设备匹配以后此函数就会执行
 * @param - dev 	: platform设备
 * @return 			: 0,成功;其他负值,失败
 */
static int led_probe(struct platform_device *dev)
{	
	int i = 0;
	int ressize[5];
	u32 val = 0;
	struct resource *ledsource[5];

	printk("led driver and device has matched!\r\n");
	/* 1、获取资源 */
	for (i = 0; i < 4; i++) {
		ledsource[i] = platform_get_resource(dev, IORESOURCE_MEM, i); /* 依次MEM类型资源 */
		if (!ledsource[i]) {
			dev_err(&dev->dev, "No MEM resource for always on\n");
			return -ENXIO;
		}
		ressize[i] = resource_size(ledsource[i]);	
	}	

	/* 2、初始化LED */
	/* 寄存器地址映射 */
 	//IMX6U_CCM_CCGR1 = ioremap(ledsource[0]->start, ressize[0]);
	SW_MUX_GPIO2_IO21 = ioremap(ledsource[0]->start, ressize[0]);
  	SW_PAD_GPIO2_IO21 = ioremap(ledsource[1]->start, ressize[1]);
	GPIO2_DR = ioremap(ledsource[2]->start, ressize[2]);
	GPIO2_GDIR = ioremap(ledsource[3]->start, ressize[3]);

	/* 设置GPIO2_IO21复用功能,将其复用为GPIO2_IO21 */
	writel(5, SW_MUX_GPIO2_IO21);
	writel(0x10B0, SW_PAD_GPIO2_IO21);

	/* 设置GPIO2_IO21为输出功能 */
	val = readl(GPIO2_GDIR);
	val &= ~(1 << 21);			/* 清除以前的设置 */
	val |= (1 << 21);			/* 设置为输出 */
	writel(val, GPIO2_GDIR);

	/* 默认关闭LED1 */
	val = readl(GPIO2_DR);
	val |= (1 << 21) ;	
	writel(val, GPIO2_DR);
	
	/* 注册字符设备驱动 */
	/*1、创建设备号 */
	if (leddev.major) {		/*  定义了设备号 */
		leddev.devid = MKDEV(leddev.major, 0);
		register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);
	} else {						/* 没有定义设备号 */
		alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);	/* 申请设备号 */
		leddev.major = MAJOR(leddev.devid);	/* 获取分配号的主设备号 */
	}
	
	/* 2、初始化cdev */
	leddev.cdev.owner = THIS_MODULE;
	cdev_init(&leddev.cdev, &led_fops);
	
	/* 3、添加一个cdev */
	cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);

	/* 4、创建类 */
	leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
	if (IS_ERR(leddev.class)) {
		return PTR_ERR(leddev.class);
	}

	/* 5、创建设备 */
	leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
	if (IS_ERR(leddev.device)) {
		return PTR_ERR(leddev.device);
	}

	return 0;
}

/*
 * @description		: platform驱动的remove函数,移除platform驱动的时候此函数会执行
 * @param - dev 	: platform设备
 * @return 			: 0,成功;其他负值,失败
 */
static int led_remove(struct platform_device *dev)
{
	//iounmap(IMX6U_CCM_CCGR1);
	iounmap(SW_MUX_GPIO2_IO21);
	iounmap(SW_PAD_GPIO2_IO21);
	iounmap(GPIO2_DR);
	iounmap(GPIO2_GDIR);

	cdev_del(&leddev.cdev);/*  删除cdev */
	unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
	device_destroy(leddev.class, leddev.devid);
	class_destroy(leddev.class);
	return 0;
}

/* platform驱动结构体 */
static struct platform_driver led_driver = {
	.driver		= {
		.name	= "imx6q-led",			/* 驱动名字,用于和设备匹配 */
	},
	.probe		= led_probe,
	.remove		= led_remove,
};
		
/*
 * @description	: 驱动模块加载函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init leddriver_init(void)
{
	return platform_driver_register(&led_driver);
}

/*
 * @description	: 驱动模块卸载函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit leddriver_exit(void)
{
	platform_driver_unregister(&led_driver);
}

module_init(leddriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZZK");



1.3、Makefile

KERNELDIR := ~/okmx6q-c/linux-4.1.15
CURRENT_PATH := $(shell pwd)

obj-m := leddevice.o leddriver.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

2. Compile and run

2.1. Compile the driver module

root@ThinkPad:~/okmx6q-c/app/platform# make ARCH=arm

root@ThinkPad:~/okmx6q-c/app/platform# cp leddevice.ko leddriver.ko /nfs_rootfs/imx6qdl-rootfs/lib/modules/4.1.15

2.2. Load the driver module

2.3 Test run

Run the test program in the previous article


LED flashing operation.

This post is from ARM Technology

Latest reply

Perfect LED driver test in platform mode   Details Published on 2024-4-20 07:28
 

6555

Posts

0

Resources
2
 

Perfect LED driver test in platform mode

This post is from ARM Technology
 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews

Room 1530, Zhongguancun MOOC Times Building, Block B, 18 Zhongguancun Street, Haidian District, Beijing 100190, China Tel:(010)82350740 Postcode:100190

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list