1.pinctrl系统是什么?
pinctrl 子系统主要完成以下工作:
(1)获取设备树中pin信息
(2)设置pin的复用功能
(3)设置pin的上下拉/速度/驱动能力等。
2.gpio子系统是什么?
就是用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO为输入输出,读取 GPIO 的值等。其主要目的是方便开发者使用gpio。
3.pinctrl系统和gpio子系统的关系
pinctrl 子系统重点是设置 PIN(有的 SOC 叫做 PAD)的复用和电气属性,如果 pinctrl 子系统将一个 PIN 复用为 GPIO 的话,那么接下来就要用到 gpio 子系统了。
4.gpio子系统的设备树配置
gpio1: gpio@0209c000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
reg表示gpio1的基地址和范围,“gpio-controller”表示 gpio1 节点是个 GPIO 控制器,#gpio-cells 应该为 2,表示一共有两个 cell,第一个 cell 为 GPIO 编号,
如下是gpio的节点配置
gpioled {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-gpioled";
led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
status = "okay";
}
“&gpio1 3”就表示 GPIO1_IO03。第二个 cell 表示GPIO 极 性 , 如 果 为 0(GPIO_ACTIVE_HIGH) 的 话 表 示 高 电 平 有 效 , 如 果 为1(GPIO_ACTIVE_LOW)的话表示低电平有效。
5.gpio_get_value 与gpio_set_value函数实现
头文件 include/linux.h/gipio.h
gpio_get_value->
__gpio_get_value->
gpiod_get_raw_value(gpio_to_desc(gpio))->
gpiod_get_raw_value_commit(desc)->
value = chip->get ? chip->get(chip, offset) : -EIO
其中chip->get是在gpio子系统驱动中注册的回调函数,一般有芯片厂家实现
struct gpio_chip {
const char *label;
struct gpio_device *gpiodev;
struct device *parent;
struct module *owner;
int (*request)(struct gpio_chip *chip,
unsigned offset);
void (*free)(struct gpio_chip *chip,
unsigned offset);
int (*get_direction)(struct gpio_chip *chip,
unsigned offset);
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*direction_output)(struct gpio_chip *chip,
unsigned offset, int value);
int (*get)(struct gpio_chip *chip,
unsigned offset);
int (*get_multiple)(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits);
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);
void (*set_multiple)(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits);
int (*set_config)(struct gpio_chip *chip,
unsigned offset,
unsigned long config);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip);
int base;
u16 ngpio;
const char *const *names;
bool can_sleep;
#if IS_ENABLED(CONFIG_GPIO_GENERIC)
unsigned long (*read_reg)(void __iomem *reg);
void (*write_reg)(void __iomem *reg, unsigned long data);
bool be_bits;
void __iomem *reg_dat;
void __iomem *reg_set;
void __iomem *reg_clr;
void __iomem *reg_dir;
bool bgpio_dir_inverted;
int bgpio_bits;
spinlock_t bgpio_lock;
unsigned long bgpio_data;
unsigned long bgpio_dir;
#endif
#ifdef CONFIG_GPIOLIB_IRQCHIP
/*
* With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
* to handle IRQs for most practical cases.
*/
/**
* @irq:
*
* Integrates interrupt chip functionality with the GPIO chip. Can be
* used to handle IRQs for most practical cases.
*/
struct gpio_irq_chip irq;
#endif
/**
* @need_valid_mask:
*
* If set core allocates @valid_mask with all bits set to one.
*/
bool need_valid_mask;
/**
* @valid_mask:
*
* If not %NULL holds bitmask of GPIOs which are valid to be used
* from the chip.
*/
unsigned long *valid_mask;
#if defined(CONFIG_OF_GPIO)
/*
* If CONFIG_OF is enabled, then all GPIO controllers described in the
* device tree automatically may have an OF translation
*/
/**
* @of_node:
*
* Pointer to a device tree node representing this GPIO controller.
*/
struct device_node *of_node;
/**
* @of_gpio_n_cells:
*
* Number of cells used to form the GPIO specifier.
*/
unsigned int of_gpio_n_cells;
/**
* @of_xlate:
*
* Callback to translate a device tree GPIO specifier into a chip-
* relative GPIO number and flags.
*/
int (*of_xlate)(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags);
#endif
};
联咏厂家的gpio_chip初始化如下:
nvt_gpio_chip_ptr->gpio_chip.get = nvt_gpio_get;
nvt_gpio_chip_ptr->gpio_chip.set = nvt_gpio_set;
nvt_gpio_chip_ptr->gpio_chip.direction_input = nvt_gpio_dir_input;
nvt_gpio_chip_ptr->gpio_chip.direction_output = nvt_gpio_dir_output;
nvt_gpio_chip_ptr->gpio_chip.get_direction = nvt_gpio_get_dir;
nvt_gpio_chip_ptr->gpio_chip.ngpio = NVT_GPIO_NUMBER;
nvt_gpio_chip_ptr->gpio_chip.to_irq = nvt_gpio_to_irq;
nvt_gpio_chip_ptr->gpio_chip.base = 0;
gpio_set_value->
__gpio_set_value->
gpiod_set_raw_value->
gpiod_set_raw_value_commit(desc, value)->
chip->set(chip, gpio_chip_hwgpio(desc), value)