130,gpio1节点:GPIO子系统初窥

1、gpio1节点

  • GPIO1控制器的寄存器基地址

  • 类似的还有gpio2~5
    imx6ull.dtsi

gpio1: gpio@209c000 {
				// 用于和gpio子系统平台驱动做匹配,对应的驱动文件为 drivers/gpio/gpio-mxc.c
				compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
				//对照数据手册,gpio1寄存器组的起始地址即为0x209c000,第二个值表示范围
				reg = <0x209c000 0x4000>;
				//描述中断相关的内容
				interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
					     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
				//描述初始化外设时钟
				clocks = <&clks IMX6UL_CLK_GPIO1>;
				//表明gpio1节点是一个gpio控制器
				gpio-controller;
				//表示要用2个cell描述一个 GPIO引脚
				#gpio-cells = <2>;
				//表示 gpio1 节点是个中断控制器
				interrupt-controller;
				//表示要用2个cell描述一个中断
				#interrupt-cells = <2>;
				//gpio编号转换成pin编号,如gpio子系统的0~9对应pinctrl的23~32号pin
				gpio-ranges = <&iomuxc  0 23 10>, <&iomuxc 10 17 6>,
					      <&iomuxc 16 33 16>;
			};

在这里插入图片描述

imx6ull-seeed-npi.dts

新增rgb_led节点,使用gpio子系统

rgb_led{
    #address-cells = <1>;
    #size-cells = <1>;
    pinctrl-names = "default";
    compatible = "fire,rgb_led";
    pinctrl-0 = <&pinctrl_rgb_led>;
    // 此属性有两个属性值
    rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW &gpio1 10 GPIO_ACTIVE_LOW>;
    rgb_led_green = <&gpio4 20 GPIO_ACTIVE_LOW>;
    rgb_led_blue = <&gpio4 19 GPIO_ACTIVE_LOW>;
    status = "okay";
};
  • rgb_led_red:自定义属性,&gpio1 4表示GPIO1_IO04,GPIO_ACTIVE_LOW表示低电平有效

2、常用函数

of_find_node_by_path()函数

函数原型:

// path:设备树节点的绝对路径
// 获取指定路径节点的device_node结构体
inline struct device_node *of_find_node_by_path(const char *path)

参数:

  • path:设备树节点的绝对路径

返回值:

  • 成功:目标节点

  • 失败:NULL

of_get_named_gpio()函数

函数原型:

static inline int of_get_named_gpio(struct device_node *np,const char *propname, int index)

参数:

  • np:指定的设备树节点
  • propname:GPIO属性名,比如上图所示的rgb_led_red 或者 rgb_led_green 或者 rgb_led_blue节点
  • index:引脚索引值,若一个属性有多个属性值,index表示选第几个属性值,取 0 表示选第一个属性值

返回值:

  • 成功:GPIO编号
  • 失败:负数

gpio_request()函数

把指定的gpio引脚添加到pin_ctrl子系统管理,避免不同的外设使用同一个引脚。
函数原型:

static inline int gpio_request(unsigned gpio, const char *label)

参数:

  • gpio:要申请的GPIO编号,就是在gpio子系统里面的编号
  • label:给 gpio 设置个名字

返回值:

  • 成功:0
  • 失败:负数

gpio_free()函数

使用完释放到在pinctrl子系统中注册的gpio编号
函数原型:

static inline void gpio_free(unsigned gpio);

参数:

  • gpio:要释放的GPIO编号(pinctrl子系统中的编号)

返回值:

gpio_direction_output()函数

函数原型:

static inline int gpio_direction_output(unsigned gpio , int value)

参数:

  • gpio:要操作的GPIO编号

  • value:设置默认输出值

返回值:

  • 成功:0
  • 失败:负数

gpio_direction_input()函数

函数原型:

int gpio_direction_input(unsigned gpio)

参数:

  • gpio:要操作的GPIO编号

返回值:

  • 成功:0
  • 失败:负数

gpio_get_value()函数

函数原型:

#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned gpio)

参数:

  • gpio:要操作的GPIO编号

返回值:

  • 成功: GPIO的电平值:1,0
  • 失败:负数

gpio_set_value()函数

函数原型:

#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned gpio, int ;)

参数:

  • gpio:要操作的GPIO编号
  • value:要设置的输出值

返回值:

3、例程

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/device.h>

#include <linux/platform_device.h>

/*------------------字符设备内容----------------------*/
#define DEV_NAME "rgb_led"
#define DEV_CNT (1)

int rgb_led_red;
int rgb_led_green;
int rgb_led_blue;

/*定义 led 资源结构体,保存获取得到的节点信息以及转换后的虚拟寄存器地址*/
struct led_resource
{
	struct device_node *device_node; //rgb_led_red的设备树节点
	void __iomem *virtual_CCM_CCGR;
	void __iomem *virtual_IOMUXC_SW_MUX_CTL_PAD;
	void __iomem *virtual_IOMUXC_SW_PAD_CTL_PAD;
	void __iomem *virtual_DR;
	void __iomem *virtual_GDIR;
};

static dev_t led_devno;					 //定义字符设备的设备号
static struct cdev led_chr_dev;			 //定义字符设备结构体chr_dev
struct class *class_led;				 //保存创建的类
struct device *device;					 // 保存创建的设备
struct device_node *rgb_led_device_node; //rgb_led的设备树节点结构体

/*定义 R G B 三个灯的led_resource 结构体,保存获取得到的节点信息*/
struct led_resource led_red;
struct led_resource led_green;
struct led_resource led_blue;

/*字符设备操作函数集,open函数*/
static int led_chr_dev_open(struct inode *inode, struct file *filp)
{
	printk("\n open form driver \n");
	return 0;
}

/*字符设备操作函数集,write函数*/
static ssize_t led_chr_dev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{

	int ret,error;
	unsigned int register_data = 0; //暂存读取得到的寄存器数据
	unsigned char receive_data[10]; //用于保存接收到的数据
	unsigned int write_data; //用于保存接收到的数据

	if(cnt>10)
			cnt =10;

	error = copy_from_user(receive_data, buf, cnt);
	if (error < 0)
	{
		return -1;
	}

	ret = kstrtoint(receive_data, 16, &write_data);
	if (ret) {
		return -1;
        }

	/*设置 GPIO1_04 输出电平*/
	if (write_data & 0x04)
	{
		gpio_set_value(rgb_led_red,0);
	}
	else
	{
		gpio_set_value(rgb_led_red,1);
	}

	/*设置 GPIO4_20 输出电平*/
	if (write_data & 0x02)
	{
		gpio_set_value(rgb_led_green,0);
	}
	else
	{
		gpio_set_value(rgb_led_green,1);
	}

	/*设置 GPIO4_19 输出电平*/
	if (write_data & 0x01)
	{
		gpio_set_value(rgb_led_blue,0);
	}
	else
	{
		gpio_set_value(rgb_led_blue,1);
	}

	return cnt;
}

/*字符设备操作函数集*/
static struct file_operations led_chr_dev_fops =
	{
		.owner = THIS_MODULE,
		.open = led_chr_dev_open,
		.write = led_chr_dev_write,
};

/*----------------平台驱动函数集-----------------*/
static int led_probe(struct platform_device *pdv)
{

	int ret = -1; //保存错误状态码
	unsigned int register_data = 0;

	printk(KERN_ALERT "\t  match successed  \n");

	/*获取rgb_led的设备树节点*/
	rgb_led_device_node = of_find_node_by_path("/rgb_led");
	if (rgb_led_device_node == NULL)
	{
		printk(KERN_ERR "\t  get rgb_led failed!  \n");
		return -1;
	}

	rgb_led_red = of_get_named_gpio(rgb_led_device_node,"rgb_led_red",0);
	if (rgb_led_red < 0)
	{
		printk(KERN_ERR "\t  rgb_led_red failed!  \n");
		return -1;
	}

	rgb_led_green = of_get_named_gpio(rgb_led_device_node,"rgb_led_green",0);
	if (rgb_led_green < 0)
	{
		printk(KERN_ERR "\t  rgb_led_green failed!  \n");
		return -1;
	}

rgb_led_blue = of_get_named_gpio(rgb_led_device_node,"rgb_led_blue",0);
	if (rgb_led_blue < 0)
	{
		printk(KERN_ERR "\t  rgb_led_blue failed!  \n");
		return -1;
	}

gpio_direction_output(rgb_led_red,1);
gpio_direction_output(rgb_led_green,1);
gpio_direction_output(rgb_led_blue,1);

	/*---------------------注册 字符设备部分-----------------*/

	//第一步
	//采用动态分配的方式,获取设备编号,次设备号为0,
	//设备名称为rgb-leds,可通过命令cat  /proc/devices查看
	//DEV_CNT为1,当前只申请一个设备编号
	ret = alloc_chrdev_region(&led_devno, 0, DEV_CNT, DEV_NAME);
	if (ret < 0)
	{
		printk("fail to alloc led_devno\n");
		goto alloc_err;
	}
	//第二步
	//关联字符设备结构体cdev与文件操作结构体file_operations
	led_chr_dev.owner = THIS_MODULE;
	cdev_init(&led_chr_dev, &led_chr_dev_fops);
	//第三步
	//添加设备至cdev_map散列表中
	ret = cdev_add(&led_chr_dev, led_devno, DEV_CNT);
	if (ret < 0)
	{
		printk("fail to add cdev\n");
		goto add_err;
	}

	//第四步
	/*创建类 */
	class_led = class_create(THIS_MODULE, DEV_NAME);

	/*创建设备*/
	device = device_create(class_led, NULL, led_devno, NULL, DEV_NAME);

	return 0;

add_err:
	//添加设备失败时,需要注销设备号
	unregister_chrdev_region(led_devno, DEV_CNT);
	printk("\n error! \n");
alloc_err:

	return -1;
}

static const struct of_device_id rgb_led[] = {
	{.compatible = "fire,rgb_led"},
	{/* sentinel */}};

/*定义平台设备结构体*/
struct platform_driver led_platform_driver = {
	.probe = led_probe,
	.driver = {
		.name = "rgb-leds-platform",
		.owner = THIS_MODULE,
		.of_match_table = rgb_led,
	}};

/*
*驱动初始化函数
*/
static int __init led_platform_driver_init(void)
{
	int DriverState;
	DriverState = platform_driver_register(&led_platform_driver);
	printk(KERN_ALERT "\tDriverState is %d\n", DriverState);
	return 0;
}

/*
*驱动注销函数
*/
static void __exit led_platform_driver_exit(void)
{
	/*删除设备*/
	device_destroy(class_led, led_devno);		  //清除设备
	class_destroy(class_led);					  //清除类
	cdev_del(&led_chr_dev);						  //清除设备号
	unregister_chrdev_region(led_devno, DEV_CNT); //取消注册字符设备

	/*注销字符设备*/
	platform_driver_unregister(&led_platform_driver);

	printk(KERN_ALERT "led_platform_driver exit!\n");
}

module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);

MODULE_LICENSE("GPL");

/**/

Makefile

KERNELDIR := /home/jl/linux/imx6ull/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga
#KERNELDIR := /home/jl/linux/imx6ull/alientek_made_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)
obj-m := test.o
res := $(patsubst %.o,%.ko,$(obj-m))
build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules  ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
copy:
	sudo cp  $(res)  ../../../nfs/rootfs/lib/modules/4.1.15/ -rf
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值