linux驱动(七)gpiolib库详解
2025-01-07 来源:cnblogs
1:什么是gpiolib,为什么要有gpiolib?
linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作用是对所有的gpio实行统一管理,因为驱动在工作的时候,会出现好几个驱动共同使用同一个gpio的情况;
这会造成混乱。所以内核提供了一些方法来管理gpio资源;
2:如何学习gpiolib
第一:gpiolib库的建立;
第二:gpiolib库的使用方法:申请、使用、释放;
3:我们首先来看一下这个文件:mach-smdkc110.c这个文件:
smdkc110_map_io
s5pv210_gpiolib_init 这个函数是gpiolib的初始化函数
__init int s5pv210_gpiolib_init(void)
{
struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
int i = 0;
for (i = 0; i < nr_chips; i++, chip++) {
if (chip->config == NULL)
chip->config = &gpio_cfg;
if (chip->base == NULL)
chip->base = S5PV210_BANK_BASE(i);
}
samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
return 0;
}
gpiolib库的初始化实质就是对这个结构体数组进行赋值;
下面看一下这个结构体
struct s3c_gpio_chip {
struct gpio_chip chip;
struct s3c_gpio_cfg *config;
struct s3c_gpio_pm *pm;
void __iomem *base;
int eint_offset;
spinlock_t lock;
#ifdef CONFIG_PM
u32 pm_save[7];
#endif
};
chpi结构体:为主要结构体
关键几个元素
label
request //申请gpio
free //释放gpio
direction_input //输入模式
direction_output //输出模式
get //读取gpio的值
set //写入gpio的值
base //gpio基地址 端口地址
ngpio //引脚地址
names //名字
struct gpio_chip {
const char *label;
struct device *dev;
struct module *owner;
int (*request)(struct gpio_chip *chip,
unsigned offset);
void (*free)(struct gpio_chip *chip,
unsigned offset);
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,
unsigned offset);
int (*direction_output)(struct gpio_chip *chip,
unsigned offset, int value);
int (*set_debounce)(struct gpio_chip *chip,
unsigned offset, unsigned debounce);
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);
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;
unsigned can_sleep:1;
unsigned exported:1;
};

内核中建立了
static struct s3c_gpio_chip s5pv210_gpio_4bit[] 这个数组,将所有的gpio的.chip结构体中的一些元素初始化
这个数组的所有元素是与数据手册中的所有gpio是一一对应的;

我们首先来分析一下.chip->base中的值 通过一下几个宏定义我们可以知道gpa0中 chip->.chip->base中的值为 0 gpa1中chip->.chip->base中的值为9 这个数字数对应端口的io口的号码;
#define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
#define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr))
S5PV210_GPIO_A0_START = 0,
S5PV210_GPIO_A1_START = S5PV210_GPIO_NEXT(S5PV210_GPIO_A0),
#define S5PV210_GPIO_NEXT(__gpio)
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
#define S5PV210_GPIO_A0_NR (8)
#define S5PV210_GPIO_A1_NR (4)
#define S5PV210_GPIO_B_NR (8)
#define S5PV210_GPIO_C0_NR (5)
----------------------------------------------------------------------------------------------------------------------------------------------
接下来是对
chip->config = &gpio_cfg;
chip->config结构体赋值;
然后是对chip->base 赋值
chip->base = S5PV210_BANK_BASE(i);
#define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)
可以看出chip->base是把gpio的虚拟地址赋值给chip->base,每个gpio的地址差0x20;
下面看一下
samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); 这个函数
void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
int nr_chips)
{
for (; nr_chips > 0; nr_chips--, chip++) {
samsung_gpiolib_add_4bit(chip);
s3c_gpiolib_add(chip);
}
}
这个函数中调用了两个函数
samsung_gpiolib_add_4bit_chips
samsung_gpiolib_add_4bit
s3c_gpiolib_add
void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
{
chip->chip.direction_input = samsung_gpiolib_4bit_input;
chip->chip.direction_output = samsung_gpiolib_4bit_output;
chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
}
这个函数的作用是对每个chip->chip的direction_input direction_output两个函数赋值
下面看一下s3c_gpiolib_add函数都做了什么:
if (!gc->direction_input)
gc->direction_input = s3c_gpiolib_input;
if (!gc->direction_output)
gc->direction_output = s3c_gpiolib_output;
if (!gc->set)
gc->set = s3c_gpiolib_set;
if (!gc->get)
gc->get = s3c_gpiolib_get;
继续对chip->中的元素进行赋值,set get赋值,
ret = gpiochip_add(gc);
最后注册这些gpio_chip结构体;
注册的实质是:在linux内核中有一个gpio_desc结构体数组,注册就是把我们封装的gpio的所有信息的结构体放到数组的格子中;
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
gpiolib库是linux内核工程师以及三星芯片厂商工程师共同完成的,内核工程师提供搭建好底层框架,三星工程师
把自己开发板的gpio初始化并注册到内核提供的数组中去;
---------------------------------------------------------------------------------------------------------------
上面讲了gpiolib库的构建,构建的实质是把所有的gpio结构体进行初始化,并且放到内核中gpio_desc这个结构体数组中;
下面看一下我们在开发驱动的时候如何使用gpiolib库
首先要了解一下linux内核工程师给我们开发的接口:
文件:/drivers/gpio/gpiolib.c文件中提供所有的接口
1:gpio_request:向内核申请gpio
int gpio_request(unsigned gpio, const char *label)
2:gpio_free对应gpio_request,是使用完gpio以后把gpio释放掉
void gpio_free(unsigned gpio)
3:gpiochip_add:向内核注册gpio
int gpiochip_add(struct gpio_chip *chip)
4:gpio_request_one 申请gpio
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
5:gpio_request_one申请gpio
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
6:gpiochip_is_requested:用来看gpio是否已经使用
const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
7:gpio_direction_input :设置gpio输入
int gpio_direction_input(unsigned gpio)
8:gpio_direction_output:gpio输出
int gpio_direction_output(unsigned gpio, int value)
9:__gpio_get_value :获取寄存器的值 这里注意由于前面加了__是内核用的函数所以我们不能用这个函数
在/arch/arm/mach-s5pv210/include/mach/gpio.h中定义了以下宏;所以我们使用的时候直接包含这个头文件使用gpio_get_value 函数即可
#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value
#define gpio_cansleep __gpio_cansleep
#define gpio_to_irq __gpio_to_irq
int __gpio_get_value(unsigned gpio)
10:__gpio_get_value :设置寄存器的值
int __gpio_get_value(unsigned gpio)
http://blog.csdn.net/tongxinv/article/details/54790792
---------------------------------------------------------------------------------------------------------------------------------
- 基于迅为iTOP-3568开发板的Linux驱动开发实战:menuconfig图形化配置实验
- 迅为工业RK3568 itop-3568开发板Linux驱动开发实战:RK3568内核模块符号导出详解
- STM32MP157 Linux系统移植开发篇12:Linux内核MIPI LCD驱动移植
- 迅为imx6ull开发板Linux I2C驱动实验-应用程序与I2C通信
- 迅为IMX6ULL开发板Linux驱动初探-最简单的设备驱动-helloworld
- 迅为IMX6ULL开发板-Linux MISC驱动-编写实验程序
- iMX6ULL终结者Linux WIFI驱动实验rtl8723 Wifi联网测试
- 迅为i.MX6ULL终结者Linux MISC驱动运行测试
- 迅为IMX6ULL开发板Linux RS232/485驱动实验(上)
- IMX6ULL开发板Linux_WIFI驱动实验
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 蓝牙信道探测技术原理与开发套件实践
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析




