一、GPIO简介
GPIO即通用输入/输出接口,每个GPIO端口可通过软件分别配置成输入或输出。
CPU提供的GPIO接口一般都是多路复用的,CPU内部提供了对应的寄存器(配置寄存器、数据寄存器、上拉/下拉寄存器、
睡眠模式配置寄存器、睡眠模式拉/下拉寄存器),通过设置对应的寄存器的值,可配置GPIO口的功能。
二、LINUX内核中对GPIO的描述
1、gpio_desc结构
在driver/gpio/gpiolib.c中定义了gpio_desc结构,用于描述GPIO
-
struct gpio_desc {
-
struct gpio_chip *chip;//描述GPIO控制器
-
unsigned long flags;
-
/* 标志位符号数字*/
-
#define FLAG_REQUESTED 0
-
#define FLAG_IS_OUT 1
-
#define FLAG_RESERVED 2
-
#define FLAG_EXPORT 3 /* protected by sysfs_lock */
-
#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */
-
#define FLAG_TRIG_FALL 5 /* trigger on falling edge */
-
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
-
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
-
-
#define ID_SHIFT 16 /* add new flags before this one */
-
-
#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
-
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
-
-
#ifdef CONFIG_DEBUG_FS
-
const char *label;
-
#endif
-
};
-
//gpio_desc用于保存所有的GPIO
-
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
2、gpio_chip结构
LINUX内核使用gpio_chip结构体描述GPIO控制器,定义在include/asm-generic/gpio.h中,
-
struct gpio_chip {
-
const char *label;
-
struct device *dev;
-
struct module *owner;
-
int (*request)(struct gpio_chip *chip,unsigned offset);//请求GPIO
-
void (*free)(struct gpio_chip *chip,unsigned offset);//释放GPIO
-
int (*direction_input)(struct gpio_chip *chip,unsigned offset);//配置GPIO为输入
-
int (*get)(struct gpio_chip *chip,unsigned offset);//获得GPIO的值
-
int (*direction_output)(struct gpio_chip *chip,unsigned offset, int value);//配置GPIO为输出
-
int (*set_debounce)(struct gpio_chip *chip,unsigned offset, unsigned debounce);//设置去抖动的时间
-
void (*set)(struct gpio_chip *chip,unsigned offset, int value);//设置GPIO的值
-
int (*to_irq)(struct gpio_chip *chip,unsigned offset);//把GPIO转换为中断号
-
void (*dbg_show)(struct seq_file *s,struct gpio_chip *chip);
-
int base;//gpio控制器的gpio开始编号
-
u16 ngpio;//该控制器控制的GPIO数量
-
const char *const *names;
-
unsigned can_sleep:1;
-
unsigned exported:1;
-
-
#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
-
*/
-
struct device_node *of_node;
-
int of_gpio_n_cells;
-
int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
-
const void *gpio_spec, u32 *flags);
-
#endif
-
};
LINUX内核中定义了一些对gpio_chip操作的方法,声明在include/asm-generic/gpio.h中,如
-
//添加gpio_chip
-
nt gpiochip_add(struct gpio_chip *chip);
-
//删除gpio_chip
-
int __must_check gpiochip_remove(struct gpio_chip *chip);
-
int __must_check gpiochip_reserve(int start, int ngpio);
-
struct gpio_chip *gpiochip_find(void *data,int (*match)(struct gpio_chip *chip,void *data));
3、各CPU体系在实现GPIO驱动时都对gpio_chip结构进行了封装,如s3c6410中,扩展了s3c_gpio_chip结构,
定义在arch/arm/plat-samsung/gpio-core.h中
-
struct s3c_gpio_chip {
-
struct gpio_chip chip;//GPIO控制器
-
struct s3c_gpio_cfg *config;//GPIO配置
-
struct s3c_gpio_pm *pm;//电源管理信息
-
void __iomem *base;//gpio配置寄存器基地址
-
int irq_base;//中断号基址
-
int group;
-
spinlock_t lock;
-
#ifdef CONFIG_PM
-
u32 pm_save[4];//挂起/恢复保存的信息
-
#endif
-
};
-
-
//GPIO配置
-
struct s3c_gpio_cfg {
-
unsigned int cfg_eint;//外部中断
-
s3c_gpio_pull_t (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs);//读取当前上拉GPIO的配置
-
int (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs,s3c_gpio_pull_t pull);//设置当前上拉GPIO的配置
-
unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs);//读GPIO的当前配置
-
int (*set_config)(struct s3c_gpio_chip *chip, unsigned offs,unsigned config);//设置GPIO的当前配置
-
};
-
-
//电源管理信息
-
struct s3c_gpio_pm {
-
void (*save)(struct s3c_gpio_chip *chip);//常规保存gpio块的状态
-
void (*resume)(struct s3c_gpio_chip *chip);//恢复GPIO的块的状态
-
};
三、S3C6410中对GPIO的实现
1、s3c_gpio_chip实例的定义
1)gpio_4bit定义,定义了GPA~GPM寄存器,每个GPIO口对应4bit
-
//arch/arm/mach-s3c64xx/gpiolib.c
-
static struct s3c_gpio_chip gpio_4bit[] = {
-
{
-
.base = S3C64XX_GPA_BASE,//gpio配置寄存器基地址
-
.config = &gpio_4bit_cfg_eint0111,//GPIO配置
-
.chip = {
-
.base = S3C64XX_GPA(0),//gpio控制器的gpio开始编号
-
.ngpio = S3C64XX_GPIO_A_NR,//该控制器控制的GPIO数量
-
.label = "GPA",
-
},
-
}, {
-
.base = S3C64XX_GPB_BASE,
-
.config = &gpio_4bit_cfg_eint0111,
-
.chip = {
-
.base = S3C64XX_GPB(0),
-
.ngpio = S3C64XX_GPIO_B_NR,
-
.label = "GPB",
-
},
-
}, {
-
.base = S3C64XX_GPC_BASE,
-
.config = &gpio_4bit_cfg_eint0111,
-
.chip = {
-
.base = S3C64XX_GPC(0),
-
.ngpio = S3C64XX_GPIO_C_NR,
-
.label = "GPC",
-
},
-
}, {
-
.base = S3C64XX_GPD_BASE,
-
.config = &gpio_4bit_cfg_eint0111,
-
.chip = {
-
.base = S3C64XX_GPD(0),
-
.ngpio = S3C64XX_GPIO_D_NR,
-
.label = "GPD",
-
},
-
}, {
-
.base = S3C64XX_GPE_BASE,
-
.config = &gpio_4bit_cfg_noint,
-
.chip = {
-
.base = S3C64XX_GPE(0),
-
.ngpio = S3C64XX_GPIO_E_NR,
-
.label = "GPE",
-
},
-
}, {
-
.base = S3C64XX_GPG_BASE,
-
.config = &gpio_4bit_cfg_eint0111,
-
.chip = {
-
.base = S3C64XX_GPG(0),
-
.ngpio = S3C64XX_GPIO_G_NR,
-
.label = "GPG",
-
},
-
}, {
-
.base = S3C64XX_GPM_BASE,
-
.config = &gpio_4bit_cfg_eint0011,
-
.chip = {
-
.base = S3C64XX_GPM(0),
-
.ngpio = S3C64XX_GPIO_M_NR,
-
.label = "GPM",
-
.to_irq = s3c64xx_gpio2int_gpm,
-
},
-
},
-
};
2)GPIO配置
-
static struct s3c_gpio_cfg gpio_4bit_cfg_noint = {
-
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,//设置GPIO的当前配置
-
.get_config = s3c_gpio_getcfg_s3c64xx_4bit,//读GPIO的当前配置
-
.set_pull = s3c_gpio_setpull_updown,//设置当前上拉GPIO的配置
-
.get_pull = s3c_gpio_getpull_updown,//读取当前上拉GPIO的配置
-
};
-
-
static struct s3c_gpio_cfg gpio_4bit_cfg_eint0111 = {
-
.cfg_eint = 7,
-
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
-
.get_config = s3c_gpio_getcfg_s3c64xx_4bit,
-
.set_pull = s3c_gpio_setpull_updown,
-
.get_pull = s3c_gpio_getpull_updown,
-
};
-
-
static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
-
.cfg_eint = 3,
-
.get_config = s3c_gpio_getcfg_s3c64xx_4bit,
-
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
-
.set_pull = s3c_gpio_setpull_updown,
-
.get_pull = s3c_gpio_getpull_updown,
-
};
3)s3c_gpio_cfg对应的函数实现
-
//设置GPIO的当前配置
-
int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
-
unsigned int off, unsigned int cfg)
-
{
-
void __iomem *reg = chip->base;//获取gpio配置寄存器基地址
-
unsigned int shift = (off & 7) * 4;
-
u32 con;
-
-
if (off < 8 && chip->chip.ngpio > 8)
-
reg -= 4;
-
-
if (s3c_gpio_is_cfg_special(cfg)) {
-
cfg &= 0xf;
-
cfg <<= shift;
-
}
-
-
con = __raw_readl(reg);
-
con &= ~(0xf << shift);//设置对应GPIO口的bit位为0
-
con |= cfg;
-
__raw_writel(con, reg);
-
-
return 0;
-
}
-
//读GPIO的当前配置
-
unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
-
unsigned int off)
-
{
-
void __iomem *reg = chip->base;//获取gpio配置寄存器基地址
-
unsigned int shift = (off & 7) * 4;
-
u32 con;
-
-
if (off < 8 && chip->chip.ngpio > 8)
-
reg -= 4;
-
-
con = __raw_readl(reg);//读取GPIO的值
-
con >>= shift;
-
con &= 0xf;
-
-
/* this conversion works for IN and OUT as well as special mode */
-
return S3C_GPIO_SPECIAL(con);
-
}
-
//设置当前上拉GPIO的配置
-
int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip,
-
unsigned int off, s3c_gpio_pull_t pull)
-
{
-
void __iomem *reg = chip->base + 0x08;//获取gpio配置寄存器基地址
-
int shift = off * 2;
-
u32 pup;
-
-
pup = __raw_readl(reg);
-
pup &= ~(3 << shift);
-
pup |= pull << shift;
-
__raw_writel(pup, reg);
-
-
return 0;
-
}
-
//读取当前上拉GPIO的配置
-
s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,
-
unsigned int off)
-
{
-
void __iomem *reg = chip->base + 0x08;
-
int shift = off * 2;
-
u32 pup = __raw_readl(reg);
-
-
pup >>= shift;
-
pup &= 0x3;
-
return (__force s3c_gpio_pull_t)pup;
-
}
4)gpio_4bit2定义,每个GPIO口对应4bit和2bit
-
static struct s3c_gpio_chip gpio_4bit2[] = {
-
{
-
.base = S3C64XX_GPH_BASE + 0x4,
-
.config = &gpio_4bit_cfg_eint0111,
-
.chip = {
-
.base = S3C64XX_GPH(0),
-
.ngpio = S3C64XX_GPIO_H_NR,
-
.label = "GPH",
-
},
-
}, {
-
.base = S3C64XX_GPK_BASE + 0x4,
-
.config = &gpio_4bit_cfg_noint,
-
.chip = {
-
.base = S3C64XX_GPK(0),
-
.ngpio = S3C64XX_GPIO_K_NR,
-
.label = "GPK",
-
},
-
}, {
-
.base = S3C64XX_GPL_BASE + 0x4,
-
.config = &gpio_4bit_cfg_eint0011,
-
.chip = {
-
.base = S3C64XX_GPL(0),
-
.ngpio = S3C64XX_GPIO_L_NR,
-
.label = "GPL",
-
.to_irq = s3c64xx_gpio2int_gpl,//把GPIO转换为中断号
-
},
-
},
-
};
-
//把GPIO转换为中断号
-
int s3c64xx_gpio2int_gpl(struct gpio_chip *chip, unsigned pin)
-
{
-
return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO;
-
}
5)gpio_2bit定义,每个GPIO口对应2bit
-
static struct s3c_gpio_chip gpio_2bit[] = {
-
{
-
.base = S3C64XX_GPF_BASE,
-
.config = &gpio_2bit_cfg_eint11,
-
.chip = {
-
.base = S3C64XX_GPF(0),
-
.ngpio = S3C64XX_GPIO_F_NR,
-
.label = "GPF",
-
},
-
}, {
-
.base = S3C64XX_GPI_BASE,
-
.config = &gpio_2bit_cfg_noint,
-
.chip = {
-
.base = S3C64XX_GPI(0),
-
.ngpio = S3C64XX_GPIO_I_NR,
-
.label = "GPI",
-
},
-
}, {
-
.base = S3C64XX_GPJ_BASE,
-
.config = &gpio_2bit_cfg_noint,
-
.chip = {
-
.base = S3C64XX_GPJ(0),
-
.ngpio = S3C64XX_GPIO_J_NR,
-
.label = "GPJ",
-
},
-
}, {
-
.base = S3C64XX_GPN_BASE,
-
.config = &gpio_2bit_cfg_eint10,
-
.chip = {
-
.base = S3C64XX_GPN(0),
-
.ngpio = S3C64XX_GPIO_N_NR,
-
.label = "GPN",
-
.to_irq = s3c64xx_gpio2int_gpn,//把GPIO转换为中断号
-
},
-
}, {
-
.base = S3C64XX_GPO_BASE,
-
.config = &gpio_2bit_cfg_eint11,
-
.chip = {
-
.base = S3C64XX_GPO(0),
-
.ngpio = S3C64XX_GPIO_O_NR,
-
.label = "GPO",
-
},
-
}, {
-
.base = S3C64XX_GPP_BASE,
-
.config = &gpio_2bit_cfg_eint11,
-
.chip = {
-
.base = S3C64XX_GPP(0),
-
.ngpio = S3C64XX_GPIO_P_NR,
-
.label = "GPP",
-
},
-
}, {
-
.base = S3C64XX_GPQ_BASE,
-
.config = &gpio_2bit_cfg_eint11,
-
.chip = {
-
.base = S3C64XX_GPQ(0),
-
.ngpio = S3C64XX_GPIO_Q_NR,
-
.label = "GPQ",
-
},
-
},
-
};
-
//把GPIO转换为中断号
-
int s3c64xx_gpio2int_gpn(struct gpio_chip *chip, unsigned pin)
-
{
-
return IRQ_EINT(0) + pin;
-
}
2、S3C6410中对GPIO初始化
在arch/arm/mach-s3c64xx/gpiolib.c中,调用三次s3c64xx_gpiolib_add()函数添加各GPIO
-
static __init int s3c64xx_gpiolib_init(void)
-
{
-
s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
-
samsung_gpiolib_add_4bit);
-
-
s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
-
samsung_gpiolib_add_4bit2);
-
-
s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit),
-
s3c64xx_gpiolib_add_2bit);
-
-
return 0;
-
}
-
//用于声明内核初始化时调用
-
core_initcall(s3c64xx_gpiolib_init);
1)s3c64xx_gpiolib_add定义
-
static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
-
int nr_chips,
-
void (*fn)(struct s3c_gpio_chip *))
-
{
-
//对各个s3c_gpio_chip调用fn和s3c_gpiolib_add函数
-
for (; nr_chips > 0; nr_chips--, chips++) {
-
if (fn)
-
(fn)(chips);
-
s3c_gpiolib_add(chips);
-
}
-
}
2)samsung_gpiolib_add_4bit定义
-
void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
-
{
-
chip->chip.direction_input = samsung_gpiolib_4bit_input;////配置GPIO为输入
-
chip->chip.direction_output = samsung_gpiolib_4bit_output;////配置GPIO为输出
-
chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
-
}
3)s3c_gpiolib_add定义
-
__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
-
{
-
struct gpio_chip *gc = &chip->chip;
-
int ret;
-
-
BUG_ON(!chip->base);
-
BUG_ON(!gc->label);
-
BUG_ON(!gc->ngpio);
-
-
spin_lock_init(&chip->lock);
-
-
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 functions\n",
-
gc->label);
-
} else
-
printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
-
#endif
-
-
//添加gpio_chip
-
ret = gpiochip_add(gc);
-
if (ret >= 0)
-
s3c_gpiolib_track(chip);
-
}
四、gpiolib.c中提供的方法
1、gpiochip_add()方法
-
//注册一个gpio_chip
-
int gpiochip_add(struct gpio_chip *chip)
-
{
-
unsigned long flags;
-
int status = 0;
-
unsigned id;
-
int base = chip->base;//获得gpio控制器的gpio开始编号
-
//检测GPIO是否合法
-
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) {
-
//如果gpio控制器的gpio开始编号,重新获取gpio控制器的gpio开始编号
-
base = gpiochip_find_base(chip->ngpio);
-
if (base < 0) {
-
status = base;
-
goto unlock;
-
}
-
chip->base = base;
-
}
-
-
/* 检测gpio_chip是否重复 */
-
for (id = base; id < base + chip->ngpio; id++) {
-
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;
-
-
/* 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 register\n",
-
chip->base, chip->base + chip->ngpio - 1,
-
chip->label ? : "generic");
-
return status;
-
}
2、gpiochip_remove()方法
-
//删除一个gpio_chip
-
int gpiochip_remove(struct gpio_chip *chip)
-
{
-
unsigned long flags;
-
int status = 0;
-
unsigned id;
-
-
spin_lock_irqsave(&gpio_lock, flags);
-
-
of_gpiochip_remove(chip);
-
-
for (id = chip->base; id < chip->base + chip->ngpio; id++) {
-
if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
-
status = -EBUSY;
-
break;
-
}
-
}
-
if (status == 0) {
-
//设置gpio_desc中对应的gpio_chip指针为空
-
for (id = chip->base; id < chip->base + chip->ngpio; id++)
-
gpio_desc[id].chip = NULL;
-
}
-
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
-
if (status == 0)
-
gpiochip_unexport(chip);
-
-
return status;
-
}
3、gpio_request()方法
-
//请求gpio
-
int gpio_request(unsigned gpio, const char *label)
-
{
-
struct gpio_desc *desc;
-
struct gpio_chip *chip;
-
int status = -EINVAL;
-
unsigned long flags;
-
-
spin_lock_irqsave(&gpio_lock, flags);
-
-
if (!gpio_is_valid(gpio))//检测GPIO是否有效
-
goto done;
-
desc = &gpio_desc[gpio];//得到gpio对应的gpio_desc
-
chip = desc->chip;//得到gpio_chip
-
if (chip == NULL)
-
goto done;
-
//加载gpio对应对应的模块
-
if (!try_module_get(chip->owner))
-
goto done;
-
-
/* NOTE: gpio_request() can be called in early boot,
-
* before IRQs are enabled, for non-sleeping (SOC) GPIOs.
-
*/
-
-
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
-
desc_set_label(desc, label ? : "?");
-
status = 0;
-
} else {
-
status = -EBUSY;
-
module_put(chip->owner);
-
goto done;
-
}
-
-
if (chip->request) {
-
/* chip->request may sleep */
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
//请求GPIO
-
status = chip->request(chip, gpio - chip->base);
-
spin_lock_irqsave(&gpio_lock, flags);
-
-
if (status < 0) {
-
desc_set_label(desc, NULL);
-
module_put(chip->owner);
-
clear_bit(FLAG_REQUESTED, &desc->flags);
-
}
-
}
-
-
done:
-
if (status)
-
pr_debug("gpio_request: gpio-%d (%s) status %d\n",
-
gpio, label ? : "?", status);
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
return status;
-
}
4、gpio_free()方法
-
//释放GPIO
-
void gpio_free(unsigned gpio)
-
{
-
unsigned long flags;
-
struct gpio_desc *desc;
-
struct gpio_chip *chip;
-
-
might_sleep();
-
-
if (!gpio_is_valid(gpio)) {
-
WARN_ON(extra_checks);
-
return;
-
}
-
-
gpio_unexport(gpio);
-
-
spin_lock_irqsave(&gpio_lock, flags);
-
-
desc = &gpio_desc[gpio];
-
chip = desc->chip;
-
if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
-
if (chip->free) {
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
might_sleep_if(chip->can_sleep);
-
//释放GPIO
-
chip->free(chip, gpio - chip->base);
-
spin_lock_irqsave(&gpio_lock, flags);
-
}
-
desc_set_label(desc, NULL);
-
module_put(desc->chip->owner);
-
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
-
clear_bit(FLAG_REQUESTED, &desc->flags);
-
} else
-
WARN_ON(extra_checks);
-
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
}
5、gpio_request_one()方法
-
//请求一个GPIO初始配置
-
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
-
{
-
int err;
-
//申请一个gpio
-
err = gpio_request(gpio, label);
-
if (err)
-
return err;
-
-
//根据flags设置gpio为输入或输出
-
if (flags & GPIOF_DIR_IN)
-
err = gpio_direction_input(gpio);
-
else
-
err = gpio_direction_output(gpio,
-
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
-
-
if (err)
-
gpio_free(gpio);
-
-
return err;
-
}
6、gpio_request_array()方法
-
//申请多个GPIO
-
int gpio_request_array(const struct gpio *array, size_t num)
-
{
-
int i, err;
-
//依次申请并设置GPIO
-
for (i = 0; i < num; i++, array++) {
-
err = gpio_request_one(array->gpio, array->flags, array->label);
-
if (err)
-
goto err_free;
-
}
-
return 0;
-
-
err_free:
-
while (i--)
-
gpio_free((--array)->gpio);
-
return err;
-
}
7、gpio_free_array()方法
-
//释放多个GPIO
-
void gpio_free_array(const struct gpio *array, size_t num)
-
{
-
while (num--)
-
gpio_free((array++)->gpio);
-
}
8、gpio_direction_input()方法
-
//设置GPIO为输入
-
int gpio_direction_input(unsigned gpio)
-
{
-
unsigned long flags;
-
struct gpio_chip *chip;
-
struct gpio_desc *desc = &gpio_desc[gpio];
-
int status = -EINVAL;
-
-
spin_lock_irqsave(&gpio_lock, flags);
-
-
if (!gpio_is_valid(gpio))//检测GPIO是否有效
-
goto fail;
-
chip = desc->chip;
-
if (!chip || !chip->get || !chip->direction_input)
-
goto fail;
-
gpio -= chip->base;
-
if (gpio >= chip->ngpio)
-
goto fail;
-
status = gpio_ensure_requested(desc, gpio);//确保GPIO已申请
-
if (status < 0)
-
goto fail;
-
-
/* now we know the gpio is valid and chip won't vanish */
-
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
-
might_sleep_if(chip->can_sleep);
-
-
if (status) {
-
status = chip->request(chip, gpio);
-
if (status < 0) {
-
pr_debug("GPIO-%d: chip request fail, %d\n",
-
chip->base + gpio, status);
-
/* and it's not available to anyone else ...
-
* gpio_request() is the fully clean solution.
-
*/
-
goto lose;
-
}
-
}
-
//设置GPIO为输入
-
status = chip->direction_input(chip, gpio);
-
if (status == 0)
-
clear_bit(FLAG_IS_OUT, &desc->flags);
-
-
trace_gpio_direction(chip->base + gpio, 1, status);
-
lose:
-
return status;
-
fail:
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
if (status)
-
pr_debug("%s: gpio-%d status %d\n",
-
__func__, gpio, status);
-
return status;
-
}
9、gpio_direction_output()方法
-
//设置GPIO为输出
-
int gpio_direction_output(unsigned gpio, int value)
-
{
-
unsigned long flags;
-
struct gpio_chip *chip;
-
struct gpio_desc *desc = &gpio_desc[gpio];
-
int status = -EINVAL;
-
-
spin_lock_irqsave(&gpio_lock, flags);
-
-
if (!gpio_is_valid(gpio))//检测GPIO是否有效
-
goto fail;
-
chip = desc->chip;
-
if (!chip || !chip->set || !chip->direction_output)
-
goto fail;
-
gpio -= chip->base;
-
if (gpio >= chip->ngpio)
-
goto fail;
-
status = gpio_ensure_requested(desc, gpio);//确保GPIO已申请
-
if (status < 0)
-
goto fail;
-
-
-
/* now we know the gpio is valid and chip won't vanish */
-
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
-
might_sleep_if(chip->can_sleep);
-
-
if (status) {
-
status = chip->request(chip, gpio);
-
if (status < 0) {
-
pr_debug("GPIO-%d: chip request fail, %d\n",
-
chip->base + gpio, status);
-
/* and it's not available to anyone else ...
-
* gpio_request() is the fully clean solution.
-
*/
-
goto lose;
-
}
-
}
-
//设置GPIO为输出
-
status = chip->direction_output(chip, gpio, value);
-
if (status == 0)
-
set_bit(FLAG_IS_OUT, &desc->flags);
-
trace_gpio_value(chip->base + gpio, 0, value);
-
trace_gpio_direction(chip->base + gpio, 0, status);
-
lose:
-
return status;
-
fail:
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
if (status)
-
pr_debug("%s: gpio-%d status %d\n",
-
__func__, gpio, status);
-
return status;
-
}
10、__gpio_get_value()方法
-
//获取GPIO的值
-
int __gpio_get_value(unsigned gpio)
-
{
-
struct gpio_chip *chip;
-
int value;
-
-
chip = gpio_to_chip(gpio);
-
WARN_ON(chip->can_sleep);
-
//获取GPIO的值
-
value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
-
trace_gpio_value(gpio, 1, value);
-
return value;
-
}
11、__gpio_set_value()方法
-
//设置GPIO的值
-
void __gpio_set_value(unsigned gpio, int value)
-
{
-
struct gpio_chip *chip;
-
-
chip = gpio_to_chip(gpio);
-
WARN_ON(chip->can_sleep);
-
trace_gpio_value(gpio, 0, value);
-
chip->set(chip, gpio - chip->base, value);
-
}
五、GPIO驱动模板
-
#define GPIO_MAJOR 230 // major device NO.
-
#define GPIO_MINOR 0 // minor device NO.
-
#define DEVICE_NAME "gpios"
-
-
#define SET_OUTPUT_LOW 0
-
#define SET_OUTPUT_HIGH 1
-
#define GET_VALUE 2
-
#define SET_INPUT 3
-
-
static struct class *gpio_class;
-
static struct gpio gpio_array[] =
-
{
-
{ GPIO_TO_PIN(0, 0), GPIOF_OUT_INIT_LOW, "RTU_WDI_SIGNAL" },
-
{ GPIO_TO_PIN(0, 1), GPIOF_OUT_INIT_HIGH, "RTU_PLC_BAK_IO1"},
-
};
-
-
static int gpio_open(struct inode *inode,struct file *file)
-
{
-
printk(KERN_WARNING"gpio open success!\n");
-
return 0;
-
}
-
-
static int gpio_release(struct inode *inode, struct file *filp)
-
{
-
printk (KERN_ALERT "Device gpio released\n");
-
return 0;
-
}
-
-
static long gpio_ioctl(struct file *file,unsigned int cmd,unsigned long gpio)
-
{
-
int i;
-
unsigned long gpio_num = (gpio/100)*16+gpio%100;
-
for (i = 0; i < ARRAY_SIZE(gpio_array); i++) {
-
if(gpio_array[i].gpio == gpio_num)
-
goto valid_gpio;
-
}
-
return -1;
-
-
valid_gpio:
-
switch(cmd)//cmd表示应用程序传入的 GPIO 动作
-
{
-
case SET_OUTPUT_LOW://0
-
{
-
gpio_direction_output(gpio_num, 0);
-
break;
-
}
-
case SET_OUTPUT_HIGH://1
-
{
-
gpio_direction_output(gpio_num, 1);
-
break;
-
}
-
case GET_VALUE://2
-
{
-
return gpio_get_value(gpio_num);
-
}
-
case SET_INPUT://3
-
{
-
gpio_direction_input(gpio_num);
-
break;
-
}
-
default:
-
{
-
printk(KERN_EMERG "GPIO command mistake!!!\n");
-
break;
-
}
-
}
-
return 0;
-
}
-
-
static const struct file_operations gpio_fops =
-
{
-
.owner = THIS_MODULE,
-
.open = gpio_open,
-
.release = gpio_release,
-
.unlocked_ioctl = gpio_ioctl,
-
};
-
-
-
//驱动加载函数
-
static int __init gpio_init(void)
-
{
-
int ret;
-
//注册一些列GPIO
-
ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array));
-
if (ret < 0)
-
{
-
printk(KERN_EMERG "GPIO request failed\n");
-
goto request_failed;
-
}
-
-
const char *name = DEVICE_NAME;
-
dev_t my_dev_no;
-
struct cdev *gpio_cdev;
-
//分配cdev结构体
-
gpio_cdev = cdev_alloc();
-
if(gpio_cdev == NULL)
-
{
-
printk(KERN_EMERG "Cannot alloc cdev\n");
-
goto request_failed;
-
}
-
//初始化cdev结构体
-
cdev_init(gpio_cdev,&gpio_fops);
-
gpio_cdev->owner=THIS_MODULE;
-
int result=alloc_chrdev_region(&my_dev_no,0,1,DEVICE_NAME); //动态分配设备号
-
if(result < 0)
-
{
-
printk(KERN_EMERG "alloc_chrdev_region failed\n");
-
goto request_failed;
-
}
-
kobject_set_name(&cdev->kobj, "%s", name);
-
ret=cdev_add(gpio_cdev,my_dev_no,1);
-
if(ret < 0)
-
{
-
printk(KERN_EMERG "GPIO register failed\n");
-
goto request_failed;
-
}
-
-
//在sysfs文件系统下创建一个类
-
gpio_class = class_create(THIS_MODULE, DEVICE_NAME);
-
//在/dev中创建设备节点
-
device_create(gpio_class, NULL, my_dev_no, NULL, DEVICE_NAME);
-
return ret;
-
-
request_failed:
-
gpio_free_array(gpio_array, ARRAY_SIZE(gpio_array));
-
return ret;
-
}
-
-
static void __exit gpio_exit(void)
-
{
-
device_destroy(gpio_class, MKDEV(GPIO_MAJOR, GPIO_MINOR));
-
class_unregister(gpio_class);
-
unregister_chrdev(GPIO_MAJOR, DEVICE_NAME);
-
}
-
-
module_init(gpio_init);
-
module_exit(gpio_exit);
-
MODULE_LICENSE("GPL");
阅读(6423) | 评论(0) | 转发(4) |