pinctrl
pinctrl是用来指定引脚复用的和配置引脚(上下拉等等),引脚上的功能有很多,比如,串口,i2c等等。pinctrl语法每个芯片公司的都有所不同。
主要参考文档:在linux内核源码Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt
修改设备树文件
my_led{
compatible="ss,led";
pinctrl-names = "default";
pinctrl-0 = <&my_pinctrl_leds>;
led-gpios= <&gpio5 3 GPIO_ACTIVE_LOW>;
};
&iomuxc_snvs {
pinctrl-names = "default_snvs";
pinctrl-0 = <&pinctrl_hog_2>;
imx6ul-evk {
pinctrl_hog_2: hoggrp-2 {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x1b0b0 /* enet1 reset */
MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06 0x1b0b0 /* enet2 reset */
MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x000110A0 /*key 1*/
>;
};
//添加节点
my_pinctrl_leds: my_pinctrl_leds {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x000110A0
>;
};
};
};
驱动文件
1.先定义paltform_driver变量及初始化
static const struct of_device_id ss_led[]={
{.compatible="ss,led"},
{},
};
static struct platform_driver chip_demo_led_driver={
.probe=led_probe,
.remove=led_remove,
.driver={
.name="ss,led",
.of_match_table=ss_led,
},
};
2.init,exit,出口入口函数,在入口函数中注册platform_driver和在出口函数中反注册platform_driver
static int __init led_init(void){
return platform_driver_register(&chip_demo_led_driver);
}
static void __exit led_exit(void){
platform_driver_unregister(&chip_demo_led_driver);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
3.定义file_operations具体变量
static struct file_operations led_operations={
.owner=THIS_MODULE,
.write=led_write,
.open=led_open,
};
4.probe函数编写
static int led_probe(struct platform_device *pplat_dev){
led_gpio_desc=gpiod_get(&(pplat_dev->dev),"led",0);
if (IS_ERR(led_gpio_desc)) {
dev_err(&(pplat_dev->dev), "Failed to get GPIO for led\n");
return PTR_ERR(led_gpio_desc);
}
major=register_chrdev(0,"ss_led",&led_operations);
led_class=class_create(THIS_MODULE,"ss_led");
if (IS_ERR(led_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "ss_led");
gpiod_put(led_gpio_desc);
return PTR_ERR(led_class);
}
device_create(led_class,NULL,MKDEV(major,0),NULL,"ss_led0");
return 0;
}
(1)获取引脚信息
//全局变量定义 static struct gpio_desc *led_gpio_desc;
//gpio_desc gpio描述符
led_gpio_desc=gpiod_get(&(pplat_dev->dev),"led",0);
(2)注册file_operations
(3) class_create和device_create
5.remove函数编写
static int led_remove(struct platform_device *pplat_dev){
device_destroy(led_class,MKDEV(major,0));
class_destroy(led_class);
unregister_chrdev(major,"ss_led");
gpiod_put(led_gpio_desc); //释放引脚
return 0;
}
6.open 和write函数编写
static int led_open (struct inode * inode, struct file * file){
int minor=iminor(inode);
//设置引脚为输出,初始时为逻辑0电平
gpiod_direction_output(led_gpio_desc,0);
return 0;
}
static ssize_t led_write (struct file * file, const char __user * user_buf, size_t size, loff_t *off_t){
int minor=iminor(file->f_inode);
char state;
int err=copy_from_user(&state,user_buf,1);
//设置引脚
gpiod_set_value(led_gpio_desc,state);
return 0;
}
7.要引用头文件
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
常用gpiod相关函数
gpiod_get_index
struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
const char *con_id,
unsigned int idx,
enum gpiod_flags flags);
其中con_id是指设备树中的gpios的名字,如下图的"led"。
led-gpios= <&gpio1 1 GPIO_ACTIVE_LOW
&gpio4 3 GPIO_ACTIVE_LOW
&gpio5 3 GPIO_ACTIVE_LOW>;
idx是第几个引脚,因为一次获得一个引脚描述符,但是有三个,这里的led引脚是GPIO5_3,所以idx是2
led_gpio_desc=gpiod_get_index(&(pplat_dev->dev),"led",2,0);
flags是配置引脚的状态,传进去在获取gpio描述符的同时设置引脚的输入,输出,这里设置为0,不配置。
/**
* Optional flags that can be passed to one of gpiod_* to configure direction
* and output value. These values cannot be OR'd.
*/
enum gpiod_flags {
GPIOD_ASIS = 0,
GPIOD_IN = GPIOD_FLAGS_BIT_DIR_SET,
GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT,
GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
GPIOD_FLAGS_BIT_DIR_VAL,
};
gpiod_count
int gpiod_count(struct device *dev, const char *con_id)
获得设备树中指定名字的引脚数量,比如上面的"led-gpios"有3个引脚信息,调用gpiod_count就可以知道有3个引脚了。
gpiod_get
struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id,
enum gpiod_flags flags)
{
return gpiod_get_index(dev, con_id, 0, flags);
}
gpio_get是获取led-gpios中的第一个gpio描述符。
gpiod_direction_input
int gpiod_direction_input(struct gpio_desc *desc)
设置引脚为输入。
gpiod_direction_output
int gpiod_direction_output(struct gpio_desc *desc, int value)
{
VALIDATE_DESC(desc);
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value;
return _gpiod_direction_output_raw(desc, value);
}
EXPORT_SYMBOL_GPL(gpiod_direction_output);
设置引脚为输出,value为引脚初始化逻辑电平。
gpiod_get_value
int gpiod_get_value(const struct gpio_desc *desc)
返回逻辑电平。
gpiod_set_value
void gpiod_set_value(struct gpio_desc *desc, int value)
设置引脚输出逻辑电平。
gpiod_put
void gpiod_put(struct gpio_desc *desc)
{
gpiod_free(desc);
}
EXPORT_SYMBOL_GPL(gpiod_put);
释放一个描述符。
gpiod_to_irq
int gpiod_to_irq(const struct gpio_desc *desc)
获得引脚对应的中断号。