imx6ull-alientk-emmc.dts
设备树源文件,在iomuxc
节点的imx6ul-evk
字节点下添加pinctrl_led
节点。(注意:节点前缀一定要为“pinctrl_
”)pinctrl_led
节点下添加“fsl,pins
”属性,对于I.MX系列的SOC而言,pinctrl驱动程序是通过读取“fsl,pins
”属性值来获取PIN的配置信息。fsl,pins
”属性中添加具体的PIN配置信息。将GPIO1_03这个引脚复用为GPIO1_IO03,电气属性为)0x10B0. pinctrl_led: ledgrp{
fls,pins = <
MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0 /* LED0 */
>;
};
/
”下创建LED节点,节点名为gpio_led
。pinctrl_led
节点添加到gpio_led
设备节点中:pinctrl-names
属性,此属性描述pinctrl名字为default
;pinctrl-0
节点,引用创建的pinctrl_led
节点,表示gpio_led
设备所使用的PIN信息保存在pinctrl_led
节点中gpio_led
设备节点中添加GPIO属性信息,表明gpio_led
所使用的GPIO1的IO03,低电平有效。 gpio_led {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-gpioled";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_led>;
led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
status = "okay";
}
pinctrl
设置imx6ull-alientek-emmc.dts
中搜索MX6UL_PAD_GPIO1_IO03
,可以找到如下内容:pinctrl_tsc
是TSC(电阻触摸屏接口)的pinctrl节点,在I.MX6U-ALPHA开发板上并没有用到TSC接口,所以可以将其使用/*
和*/
符号屏蔽掉。imx6ull-alientek-emmc.dts
中搜索gpio1 3
,可以找到如下内容:然后我们就可使用make dtbs
命令重新编译设备树,使用新编译的设备树文件启动Linux 系统,启动后进入“/porc/device-tree
”目录中查看gpio_led
节点的存在:
驱动代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/***************************************************************
文件名 : gpioled_drv.c
描述 : gpioled 驱动文件
***************************************************************/
#define DEV_NAME "gpioled_drv" /* 设备名 */
/* 1. 确定主设备号 */
static int major = 0; /* 主设备号 */
static struct class *gpioled_class; /*gpioled设备类*/
static struct device_node *gpioled_nd; /*gpioled设备节点*/
int led_gpio_num; /*led使用的gpio编号*/
/* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */
/*
* @description : 打开设备
* @param - inode : 传递给驱动的inode
* @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
* 一般在open的时候将private_data指向设备结构体。
* @return : 0 成功;其他 失败
*/
static int gpioled_drv_open (struct inode *node, struct file *file)
{
unsigned int ret;
/* 设置LED所使用的GPIO*/
/* 1,获取设备节点:gpioled_nd*/
gpioled_nd = of_find_node_by_path("/gpio_led");
if(gpioled_nd == NULL)
{
printk("gpioled node cannot found!!!\r\n");
return -EINVAL;
}
/* 2,获取LED所使用的GPIO编号 */
led_gpio_num = of_get_named_gpio(gpioled_nd, "led-gpio", 0);
if(led_gpio_num < 0)
{
printk("cannot get led-gpio!!!\r\n");
return -EINVAL;
}
/* 3,设置GPIO_IO03为输出,并且输出高电平,默认关闭LED灯*/
ret = gpio_direction_output(led_gpio_num,1);
if(ret < 0)
{
printk("can't set gpio!!!\r\n");
}
return 0;
}
/*
* @description : 从设备读取数据
* @param - filp : 要打开的设备文件(文件描述符)
* @param - buf : 返回给用户空间的数据缓冲区
* @param - size : 要读取的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 读取的字节数,如果为负值,表示读取失败
*/
static ssize_t gpioled_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
return 0;
}
/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - size : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t gpioled_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
unsigned char status_buf[1];
err = copy_from_user(status_buf, buf, size);
if(err < 0){
printk("kernel recevdata faigpioled!\r\n");
}
if(status_buf[0] == 1) //点亮gpioled
{
/* 设置GPIO1_DR输出低电平*/
gpio_set_value(led_gpio_num,0);
printk("set:gpioled ON \n");
}
else if(status_buf[0] == 0) //熄灭gpioled
{
/* 设置GPIO1_IO03输出高电平*/
gpio_set_value(led_gpio_num,1);
printk("set:gpioled OFF \n");
}
return 1;
}
/*
* @description : 关闭/释放设备
* @param - filp : 要关闭的设备文件(文件描述符)
* @return : 0 成功;其他 失败
*/
static int gpioled_drv_close (struct inode *node, struct file *file)
{
return 0;
}
/* 2. 定义自己的file_operations结构体 */
static struct file_operations gpioled_drv_fops = {
.owner = THIS_MODULE,
.open = gpioled_drv_open,
.read = gpioled_drv_read,
.write = gpioled_drv_write,
.release = gpioled_drv_close,
};
/* 4. 把file_operations结构体告诉内核:注册驱动程序 */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
/* @description : 驱动入口函数
* @return : 0 成功;其他 失败 */
static int __init gpioled_init(void)
{
int err;
/* 注册字符设备驱动 参数1:主设备号(为0自动获得设备号);参数2:设备名;参数3:file_operations结构体*/
major = register_chrdev(0, DEV_NAME, &gpioled_drv_fops);
/*创建设备类*/
gpioled_class = class_create(THIS_MODULE, "gpioled_class");
err = PTR_ERR(gpioled_class);
if (IS_ERR(gpioled_class)) {
unregister_chrdev(major, DEV_NAME);
return -1;
}
/*创建设备节点 参数1:设备类结构体;参数2:NULL;参数3:设备号(主+次);参数4:NULL;参数5:设备名*/
device_create(gpioled_class, NULL, MKDEV(major, 0), NULL, DEV_NAME); /* /dev/gpioled */
printk("gpioled_drv insmod OK !\r\n");
return 0;
}
/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */
static void __exit gpioled_exit(void)
{
device_destroy(gpioled_class, MKDEV(major, 0));
class_destroy(gpioled_class);
unregister_chrdev(major, "gpioled");
printk("gpioled_drv exit!\r\n");
}
/* 7. 其他完善:提供设备信息,自动创建设备节点 */
/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(gpioled_init);
module_exit(gpioled_exit);
/* LICENSE和作者信息 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("william");