字符设备驱动(1)代码分析---之gpio_to_irq
2025-01-07 来源:cnblogs
/**************************************************************
gpio_to_irq(S5PV210_GPH2(0))
**************************************************************/
4 #define gpio_to_irq __gpio_to_irq
5
6 int __gpio_to_irq(unsigned gpio)
7 {
8 struct gpio_chip *chip;
9 chip = gpio_to_chip(S5PV210_GPH2(0));
static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
{
return gpio_desc[S5PV210_GPH2(0)].chip;
//参考gpio-s5pv210.c中
//samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips)函数
//gpio_desc[id].chip = chip;
}
10 return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
11 //s5pv210_gpio_4bit
12 }
int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
{
//获得gpio_chip结构体所在的父结构体s3c_gpio_chip的指针
struct s3c_gpio_chip *s3c_chip = container_of(chip,struct s3c_gpio_chip, chip);
//获取虚拟映射机制中定义的终端号
return s3c_chip->irq_base + offset;
#define IRQ_EINT(x) ((x) < 16 ? ((x) + S5P_EINT_BASE1)
: ((x) - 16 + S5P_EINT_BASE2))
#define S5P_EINT_BASE2 (IRQ_VIC_END + 1)
#define IRQ_VIC_END S5P_IRQ_VIC3(31)
#define S5P_IRQ_VIC3(x) (S5P_VIC3_BASE + (x))
#define S5P_VIC3_BASE S5P_IRQ(96)
#define S5P_IRQ(x) ((x) + S5P_IRQ_OFFSET)
#define S5P_IRQ_OFFSET (32)
#define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0))
#define S5P_IRQ_VIC0(x) (S5P_VIC0_BASE + (x))
#define S5P_VIC0_BASE S5P_IRQ(0)
}
static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
{
.chip = {
.base = S5PV210_GPA0(0),
.ngpio = S5PV210_GPIO_A0_NR,
.label = 'GPA0',
},
},
...............
...............
{
.base = (S5P_VA_GPIO + 0xC40),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(16),
.chip = {
.base = S5PV210_GPH2(0),
.ngpio = S5PV210_GPIO_H2_NR,
.label = 'GPH2',
.to_irq = samsung_gpiolib_to_irq,
},
},
{
.base = (S5P_VA_GPIO + 0xC60),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(24),
.chip = {
.base = S5PV210_GPH3(0),
.ngpio = S5PV210_GPIO_H3_NR,
.label = 'GPH3',
.to_irq = samsung_gpiolib_to_irq,
},
},
};
1 static __init int s5pv210_gpiolib_init(void)
2 {
3 struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
4 int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
for (i = 0; i < nr_chips; i++, chip++) {
if (chip->config == NULL) {
chip->config = &gpio_cfg;
chip->group = gpioint_group++;
}
if (chip->base == NULL)
chip->base = S5PV210_BANK_BASE(i);
}
6 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);
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);
}
s3c_gpiolib_add(chip);
__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
//将s3c_gpio_chip 结构体变量s5pv210_gpio_4bit数组中的每一个数组变量 '.chip'传递给gpio_chip结构体指针gc
struct gpio_chip *gc = &chip->chip;
//gc = {
// .base = S5PV210_GPH2(0),
// .ngpio = S5PV210_GPIO_H2_NR,
// .label = 'GPH2',
// .to_irq = samsung_gpiolib_to_irq,
// },
int ret;
spin_lock_init(&chip->lock);
//给gc结构体指针其他结构体成员赋值
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;
#ifdef CONFIG_PM
if (chip->pm != NULL) {
if (!chip->pm->save || !chip->pm->resume)
printk(KERN_ERR 'gpio: %s has missing PM functionsn',
gc->label);
} else
printk(KERN_ERR 'gpio: %s has no PM functionn', gc->label);
#endif
// gpiochip_add() prints own failure message on error.
ret = gpiochip_add(gc);
int gpiochip_add(struct gpio_chip *chip){
unsigned long flags; int status = 0; unsigned id;
int base = chip->base; //base = S5PV210_GPH2(0)
//查看获得的gpio_chip结构体指针基址和范围是否在有效范围之内
if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
&& base >= 0) {
status = -EINVAL;
goto fail;
}
spin_lock_irqsave(&gpio_lock, flags);
if (base < 0) {
base = gpiochip_find_base(chip->ngpio);
if (base < 0) {
status = base;
goto unlock;
}
chip->base = base;
}
//these GPIO numbers must not be managed by another gpio_chip
//遍历某个GPIO端口组的所有IO,如:S5PV210_GPH2端口组的8个IO口S5PV210_GPH2(0)~(7)
for (id = base; id < base + chip->ngpio; id++)
{
//正常状态gpio_desc[base].chip未被初始化,所以各个成员为NULL
if (gpio_desc[id].chip != NULL) {
status = -EBUSY;
break;
}
}
if (status == 0) {
for (id = base; id < base + chip->ngpio; id++) {
gpio_desc[id].chip = chip;
//至此完成gpio_desc[S5PV210_GPH2(0)].chip的赋值,作为返回值在gpio_to_chip()中返回
// REVISIT: most hardware initializes GPIOs as
* inputs (often with pullups enabled) so power
* usage is minimized. Linux code should set the
* gpio direction first thing; but until it does,
* we may expose the wrong direction in sysfs.
gpio_desc[id].flags = !chip->direction_input
? (1 << FLAG_IS_OUT)
: 0;
}
}
of_gpiochip_add(chip);
unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
goto fail;
status = gpiochip_export(chip);
if (status)
goto fail;
return 0;
fail:
//failures here can mean systems won't boot...
pr_err('gpiochip_add: gpios %d..%d (%s) failed to registern',
chip->base, chip->base + chip->ngpio - 1,
chip->label ? : 'generic');
return status;
}
if (ret >= 0)
s3c_gpiolib_track(chip)
}
}
}
7 s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
8
9 return 0;
10 }
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析
- 蓝牙信道探测技术原理与开发套件实践
- 意法半导体中国本地造STM32微控制器启动规模量产




