-
一、概述
-
GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋友应该比较熟悉寄存器级的驱动。
-
-
GPIO的驱动主要就是读取GPIO口的状态,或者设置GPIO口的状态。就是这么简单,但是为了能够写好的这个驱动,在LINUX上作了一些软件上的分层。为了让其它驱动可以方便的操作到GPIO,在LINUX里实现了对GPIO操作的统一接口,这个接口实则上就是GPIO驱动的框架,具体的实现文件为gpiolib.c在配置内核的时候,我们必须使用CONFIG_GENERIC_GPIO这个宏来支持GPIO驱动。
-
-
GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,即各个板卡都有实现自己的gpio_chip控制模块:request, free, input,output, get,set,irq...然后把控制模块注册到内核中,这时会改变全局gpio数组:gpio_desc[]. 当用户请求gpio时,就会到这个数组中找到,并调用这个GPIO对应的gpio_chip的处理函数。gpio实现为一组可用的
gpio_chip, 由驱动传入对应 gpio的全局序号去 request, dataout ,datain, free. 这时会调用gpio_chip中具体的实现。
-
gpio是一组可控件的脚,由多个寄存器同时控制。通过设置对应的寄存器可以达到设置GPIO口对应状态与功能。数据状态,输入输出方向,清零,中断(那个边沿触发), 一般是一组(bank)一组的。
-
寄存器读写函数: __raw_writel() __raw_writeb() __raw_readl() __raw_readb()
-
-
二、linux 中GPIO模型的结构
-
//表示一个gpio口,含对应的gpio_chip.
-
//对于每一个gpio,都有一个gpio描述符,这个描述符包含了这个gpio所属的控制器即chip和一些标志,label等
-
struct gpio_desc {
-
struct gpio_chip *chip;
-
unsigned long flags;
-
/* flag symbols are bit numbers */
-
#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 FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
-
#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
-
-
#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
-
};
-
//采用了一个具有ARCH_NR_GPIOS大小的gpio描述符数组。这个描述符数组便代表了系统所有的gpio。
-
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];//ARCH_NR_GPIOS=144,即系统现在有144个GPIO口
-
-
//static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//将144个GPIO分成每32个一组
-
//一组GPIO控制器结构,例如GPIO0和GPIO1是一组(共32个GPIO口),共用一组寄存器,所以GPIO0和GPIO1荷载一起用chips[0]来控制
-
///共有144个GPIO,分为4组(GPIO0~GPIO8),每组有2个banks(即GPIO0和GPIO1为1组),每组最多可以有32个GPIO,每组的控制寄存器空间有10个。
-
struct davinci_gpio_controller {
-
struct gpio_chip chip;//每组对应的gpio_chip
-
int irq_base;//每组对应的中断
-
spinlock_t lock;//自旋锁
-
void __iomem *regs;//每组的寄存器地址
-
void __iomem *set_data;//设置数据寄存器地址
-
void __iomem *clr_data;//清除数据寄存器地址
-
void __iomem *in_data;//输入数据寄存器地址
-
};
-
-
//每一个davinci_gpio_controller结构都对应于一个gpio_chip结构,gpio_chip既可看成是davinci_gpio_controller结构的补充
-
//表示一个gpio controller.通过这个结构抽象化所有的GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO。
-
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 (*get_direction)(struct
gpio_chip *chip,unsigned offset);
-
int (*direction_input)(struct
gpio_chip *chip,unsigned offset);//配置gpio为输入,返回当前gpio状态
-
int (*get)(struct
gpio_chip *chip,unsigned offset);//获取gpio的状态
-
int (*direction_output)(struct
gpio_chip *chip,unsigned offset, int value);//配置gpio为输出,并设置为value
-
int (*set_debounce)(struct
gpio_chip *chip,unsigned offset, unsigned debounce);//设置消抖动时间,尤其是gpio按键时有用
-
void (*set)(struct
gpio_chip *chip,unsigned offset, int value);//设置gpio为value值
-
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控制器说控制的gpio数
-
const char *const *names;
-
unsigned can_sleep:1;
-
unsigned exported:1;
-
-
#if defined(CONFIG_OF_GPIO)
-
struct device_node *of_node;
-
int of_gpio_n_cells;
-
int (*of_xlate)(struct
gpio_chip *gc,const struct of_phandle_args *gpiospec, u32 *flags);
-
#endif
-
#ifdef CONFIG_PINCTRL
-
struct list_head pin_ranges;
-
#endif
-
};
-
-
//GPIO寄存器结构
-
struct davinci_gpio_regs {
-
u32 dir; // gpio方向设置寄存器
-
u32 out_data; // gpio设置为输出时,表示输出状态(0或1)
-
u32 set_data; // gpio设置为输出时,用于输出高电平
-
u32 clr_data; // gpio设置为输出时,用于输出低电平
-
u32 in_data; // gpio设置为输入时,用于读取输入值
-
u32 set_rising; // gpio中断上升沿触发设置
-
u32 clr_rising; // gpio中断上升沿触发清除
-
u32 set_falling; // gpio中断下降沿触发设置
-
u32 clr_falling; // gpio中断下降沿触发清除
-
u32 intstat; // gpio中断状态位,由硬件设置,可读取,写1时清除。
-
};
-
-
struct gpio {
-
unsigned gpio;//gpio号
-
unsigned long flags;//gpio标志
-
const char *label;//gpio名
-
};
-
-
三、GPIO的初始化
-
1.首先设置GPIO的管脚复用寄存器
-
static __init void da850_evm_init(void)
-
{
-
//.......
-
ret = davinci_cfg_reg_list(da850_gpio_test_pins);
-
if (ret)
-
pr_warning("da850_evm_init: gpio test ping mux setup failed: %d\n", ret);
-
//.......
-
}
-
-
2.根据板级结构的资源初始化chips数组,此函数在系统初始化时自动调用
-
static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//将144个GPIO分成每32个一组
-
static int __init davinci_gpio_setup(void)
-
{
-
int i, base;
-
unsigned ngpio;
-
struct davinci_soc_info *soc_info = &davinci_soc_info;//板级资源结构
-
struct davinci_gpio_regs *regs;
-
-
if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)//判断GPIO类型
-
return 0;
-
-
ngpio = soc_info->gpio_num;//GPIO数量144
-
if (ngpio == 0) {
-
pr_err("GPIO setup: how many GPIOs?\n");
-
return -EINVAL;
-
}
-
-
if (WARN_ON(DAVINCI_N_GPIO < ngpio))//DAVINCI_N_GPIO=144
-
ngpio = DAVINCI_N_GPIO;
-
-
gpio_base = ioremap(soc_info->gpio_base, SZ_4K);//将GPIO的寄存器物理基地址(#define
DA8XX_GPIO_BASE 0x01e26000)映射到内存中
-
if (WARN_ON(!gpio_base))
-
return -ENOMEM;
-
-
//共有144个GPIO,分为4组(GPIO0~GPIO8),每组有2个banks(即GPIO0和GPIO1为1组),每组最多可以有32个GPIO,每组的控制寄存器空间有10个。
-
//chips[0]--chips[4],base值为0,32,64,96,128,ngpio分别为:32,32,32,32,16
-
for (i = 0, base = 0; base
< ngpio; i++, base
+= 32) {
-
chips[i].chip.label = "DaVinci";
-
//设置操作函数
-
chips[i].chip.direction_input = davinci_direction_in;
-
chips[i].chip.get = davinci_gpio_get;
-
chips[i].chip.direction_output = davinci_direction_out;
-
chips[i].chip.set = davinci_gpio_set;
-
-
chips[i].chip.base = base;//每一组开始的GPIO号
-
//每组控制的GPIO个数,一般为32个
-
chips[i].chip.ngpio = ngpio
- base;
-
if (chips[i].chip.ngpio
> 32)
-
chips[i].chip.ngpio = 32;
-
-
spin_lock_init(&chips[i].lock);
-
//找到这组GPIO的寄存器地址,初始化chips结构
-
regs = gpio2regs(base);
-
chips[i].regs = regs;//设置每组的寄存器
-
chips[i].set_data = ?s->set_data;
-
chips[i].clr_data = ?s->clr_data;
-
chips[i].in_data = ?s->in_data;
-
-
gpiochip_add(&chips[i].chip);//注册gpio_chip
-
}
-
//chips数组添加到板级资源中
-
soc_info->gpio_ctlrs = chips;
-
soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
-
-
davinci_gpio_irq_setup();//设置GPIO中断
-
return 0;
-
}
-
pure_initcall(davinci_gpio_setup);//linux初始化时会自动调用
-
-
static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
-
{
-
void __iomem *ptr;
-
-
//根据GPIO的基地址累加,其中基地址(gpio_base+0)是REVID(Revision ID Register)寄存器
-
//(gpio_base+8)是BINTEN (GPIO Interrupt Per-Bank Enable Register)寄存器
-
//所以第一组寄存器从基地址+0x10开始
-
if (gpio < 32 * 1)
-
ptr = gpio_base + 0x10;
-
else if (gpio < 32 * 2)
-
ptr = gpio_base + 0x38;
-
else if (gpio < 32 * 3)
-
ptr = gpio_base + 0x60;
-
else if (gpio < 32 * 4)
-
ptr = gpio_base + 0x88;
-
else if (gpio < 32 * 5)
-
ptr = gpio_base + 0xb0;
-
else
-
ptr = NULL;
-
return ptr;
-
}
-
-
int gpiochip_add(struct gpio_chip *chip)
-
{
-
unsigned long flags;
-
int status = 0;
-
unsigned id;
-
int base = chip->base;
-
-
//检测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);
-
-
//如果这组GPIO的起始号小于0,则动态的分配gpio的开始索引。
-
if (base < 0) {
-
base = gpiochip_find_base(chip->ngpio);//这个函数在gpiolib.c中,在gpio_desc[]中分配chip->ngpio个空间(从最后往前分配),返回第一个index
-
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;
-
}
-
}
-
//填充gpio_desc,将该组内的每个GPIO口的gpio_desc结构和该组的控制结构chip联系起来
-
if (status == 0) {
-
for (id = base; id < base + chip->ngpio; id++) {
-
gpio_desc[id].chip = chip;
-
gpio_desc[id].flags = !chip->direction_input? (1 << FLAG_IS_OUT): 0;//设置GPIO口标志
-
}
-
}
-
of_gpiochip_add(chip);
-
-
unlock:
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
-
if (status)
-
goto fail;
-
-
status = gpiochip_export(chip);//与sysfs文件系统有关,这里不关心
-
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;
-
}
-
-
四.gpio的申请
-
//所谓申请就是检测GPIO描述符desc->flags的FLAG_REQUESTED标志,已申请的话该标志是1,否则是0
-
//往往多个gpio作为一个数组来进行申请
-
int gpio_request_array(struct gpio *array, size_t num)
-
{
-
int i, err;
-
-
for (i = 0; i <
num; i++, array++) {//遍历数组中的每一个GPIO,gpio是GPIO号,flags是输入输出标志等,label是其取一个名字
-
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;
-
}
-
-
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
-
{
-
int err;
-
-
//gpio则为你要申请的哪一个管脚,label则是为其取一个名字。
-
err = gpio_request(gpio, label);
-
if (err)
-
return err;
-
-
if (flags & GPIOF_DIR_IN)//GPIO标志是输入
-
err = gpio_direction_input(gpio);//设置管脚为输入
-
else//GPIO标志是输出
-
err = gpio_direction_output(gpio,(flags
& GPIOF_INIT_HIGH) ? 1 : 0);//根据标志确定输出1还是0
-
-
if (err)
-
gpio_free(gpio);
-
-
return err;
-
}
-
-
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))//判断是否有效,也就是参数的取值范围判断
-
goto done;
-
-
//根据GPIO号找到对应的GPIO描述符结构
-
desc = &gpio_desc[gpio];
-
chip = desc->chip;//找到该GPIO所在的组控制器
-
if (chip == NULL)
-
goto done;
-
-
//计数加1
-
if (!try_module_get(chip->owner))
-
goto done;
-
-
//这里测试并设置flags的第FLAG_REQUESTED位,如果没有被申请就返回该位的原值0
-
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
-
desc_set_label(desc, label ? : "?");//设置GPIO描述符结构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);
-
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;
-
}
-
-
五.GPIO的操作
-
1.设置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);
-
-
//判断GPIO号是否有效
-
if (!gpio_is_valid(gpio))
-
goto fail;
-
//找到GPIO对应的gpio_chip结构
-
chip = desc->chip;
-
if (!chip || !chip->get || !chip->direction_input)
-
goto fail;
-
-
//确保此GPIO是在此组内,chip->base是此组GPIO的起始号,chip->ngpio是此组GPIO的个数
-
gpio -= chip->base;
-
if (gpio >= chip->ngpio)
-
goto fail;
-
-
//确保GPIO已申请
-
status = gpio_ensure_requested(desc, gpio);
-
if (status < 0)
-
goto fail;
-
-
//到这里可以确保GPIO是有效的
-
spin_unlock_irqrestore(&gpio_lock, flags);
-
-
might_sleep_if(chip->can_sleep);
-
//status=0
-
if (status) {
-
status = chip->request(chip, gpio);
-
if (status < 0) {
-
pr_debug("GPIO-%d: chip request fail, %d\n",chip->base +
gpio, status);
-
goto lose;
-
}
-
}
-
//调用底层的已经设置过的操作,这里即davinci_direction_in
-
status = chip->direction_input(chip, gpio);
-
if (status == 0)//返回成功
-
clear_bit(FLAG_IS_OUT, &desc->flags);//清除输出标志
-
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;
-
}
-
-
int gpio_direction_output(unsigned gpio, int value)
-
{
-
//.........GPIO的检查,同上函数
-
-
//调用底层的已经设置过的操作,这里即davinci_direction_out
-
status = chip->direction_output(chip, gpio, value);
-
if (status == 0)//返回成功
-
set_bit(FLAG_IS_OUT, &desc->flags);//设置输出标志
-
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;
-
}
-
-
//根据前边对gpio_chip结构的初始化,会调用\arch\arm\mach-davinci\gpio.c里的函数
-
static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
-
{
-
return __davinci_direction(chip, offset, false, 0);
-
}
-
-
static int davinci_direction_out(struct gpio_chip *chip, unsigned offset, int
value)
-
{
-
return __davinci_direction(chip, offset, true, value);
-
}
-
-
static inline int __davinci_direction(struct gpio_chip *chip,unsigned
offset, bool out, int value)
-
{
-
struct davinci_gpio_controller *d = chip2controller(chip);
-
struct davinci_gpio_regs __iomem *g = d->regs;//找到此组GPIO的控制寄存器地址
-
unsigned long flags;
-
u32 temp;
-
u32 mask = 1 << offset;
-
-
spin_lock_irqsave(&d->lock, flags);
-
temp = __raw_readl(&g->dir);//读出当前寄存器的输入输出方向
-
-
if (out) {//为1设置输出
-
temp &= ~mask;
-
__raw_writel(mask, value ? &g->set_data : &g->clr_data);//确定是用于输出高电平还是输出低电平
-
}
-
else {//为0设置为输入
-
temp |= mask;
-
}
-
__raw_writel(temp, &g->dir);//写入方向寄存器
-
spin_unlock_irqrestore(&d->lock, flags);
-
-
return 0;
-
}
-
-
2.获取gpio的状态
-
int __gpio_get_value(unsigned gpio)
-
{
-
struct gpio_chip *chip;
-
-
chip = gpio_to_chip(gpio);
-
WARN_ON(chip->can_sleep);
-
return chip->get ? chip->get(chip, gpio - chip->base) : 0;//调用davinci_gpio_get
-
}
-
-
static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
-
{
-
struct davinci_gpio_controller *d = chip2controller(chip);
-
struct davinci_gpio_regs __iomem *g = d->regs;
-
-
return (1 << offset) & __raw_readl(&g->in_data);
-
}
-
-
3.设置GPIO的值
-
void __gpio_set_value(unsigned gpio, int value)
-
{
-
struct gpio_chip *chip;
-
-
chip = gpio_to_chip(gpio);
-
WARN_ON(chip->can_sleep);
-
chip->set(chip, gpio - chip->base, value);//调用davinci_gpio_set
-
}
-
-
static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int
value)
-
{
-
struct davinci_gpio_controller *d = chip2controller(chip);
-
struct davinci_gpio_regs __iomem *g = d->regs;
-
-
__raw_writel((1 << offset), value
? &g->set_data : &g->clr_data);
-
}
-
-
六、GPIO驱动编写
-
1.首先要申请GPIO口
-
2.注册设备
-
3.创建GPIO的sysfs相关文件
-
#define GPIO_MAJOR 199 // major device NO.
-
#define GPIO_MINOR 0 // minor device NO.
-
#define DEVICE_NAME "omapl138_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" },will request fail*/
-
{ GPIO_TO_PIN(0, 1), GPIOF_OUT_INIT_HIGH, "RTU_PLC_BAK_IO1"},
-
{ GPIO_TO_PIN(0, 2), GPIOF_OUT_INIT_LOW, "RTU_CHG_EN" },
-
{ GPIO_TO_PIN(0, 3), GPIOF_IN, "RTU_CHG_PG" },
-
{ GPIO_TO_PIN(0, 5), GPIOF_IN, "RTU_USB_OC_OUT" },
-
{ GPIO_TO_PIN(0, 6), GPIOF_OUT_INIT_LOW, "RTU_RUN_IND_LED" },
-
{ GPIO_TO_PIN(1, 10), GPIOF_IN, "RTU_TSC_BUSY"},
-
{ GPIO_TO_PIN(1, 11), GPIOF_IN, "RTU_PENIRQn" },
-
{ GPIO_TO_PIN(1, 12), GPIOF_OUT_INIT_LOW, "RTU_uP_Q26x_RESET" },
-
{ GPIO_TO_PIN(1, 13), GPIOF_OUT_INIT_HIGH, "RTU_uP_GPRS_PWR_EN" },
-
{ GPIO_TO_PIN(1, 14), GPIOF_OUT_INIT_HIGH, "RTU_uP_Q26x_ON/OFF" },
-
{ GPIO_TO_PIN(2, 1), GPIOF_OUT_INIT_LOW, "RTU_PLC_Reset" },
-
{ GPIO_TO_PIN(2, 2), GPIOF_OUT_INIT_LOW, "RTU_PLC_T_Reg" },
-
{ GPIO_TO_PIN(2, 4), GPIOF_OUT_INIT_LOW, "RTU_PLC_BAK_IO2" },
-
{ GPIO_TO_PIN(2, 5), GPIOF_OUT_INIT_LOW, "RTU_RS485_RE" },
-
{ GPIO_TO_PIN(2, 15), GPIOF_OUT_INIT_HIGH, "RTU_CHPWR_CS" },
-
{ GPIO_TO_PIN(3, 9), GPIOF_OUT_INIT_HIGH, "RTU_RS485_DE" },
-
{ GPIO_TO_PIN(6, 1), GPIOF_OUT_INIT_HIGH, "RTU_uP_VPIF_CLKO3" },
-
{ GPIO_TO_PIN(6, 9), GPIOF_IN, "RTU_KEY_IN2" },
-
{ GPIO_TO_PIN(6, 11), GPIOF_IN, "RTU_ALARM_IN5" },
-
{ GPIO_TO_PIN(6, 15), GPIOF_OUT_INIT_HIGH,"RTU_uP_RESETOUTn" },
-
};
-
-
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 int gpio_read(struct file*f,char *dst,size_t size,loff_t*offset)
-
{
-
unsigned char num;
-
__copy_to_user(&num,dst,1);
-
#ifdef DEBUG
-
printk("__copy_to_user:%d\n",num);
-
#endif
-
-
return 0;
-
}
-
-
static int gpio_write(struct file*f,const char *src,size_t size,loff_t
*offset)
-
{
-
unsigned char num;
-
__copy_from_user(&num,src,1);
-
#ifdef DEBUG
-
printk("__copy_from_user:%d\n",num);
-
#endif
-
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,
-
.read = gpio_read,
-
.write = gpio_write,
-
.unlocked_ioctl = gpio_ioctl,
-
};
-
-
static int __init gpio_init(void) /*内核初始化会调用该函数*/
-
{
-
int ret;
-
-
ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array));
-
if (ret < 0)
-
{
-
printk(KERN_EMERG "GPIO request failed\n");
-
goto request_failed;
-
}
-
-
dev_t my_dev_no;
-
struct cdev *gpio_cdev;
-
gpio_cdev = cdev_alloc();
-
if(gpio_cdev == NULL)
-
{
-
printk(KERN_EMERG "Cannot alloc cdev\n");
-
goto request_failed;
-
}
-
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;
-
}
-
ret=cdev_add(gpio_cdev,my_dev_no,1);
-
-
-
ret = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &gpio_fops);//驱动字符设备
-
if(ret < 0)
-
{
-
printk(KERN_EMERG "GPIO register failed\n");
-
goto request_failed;
-
}
-
-
//在sysfs文件系统下创建一个类
-
gpio_class = class_create(THIS_MODULE, DEVICE_NAME);
-
//device_create-->device_create_vargs-->device_register创建相应的sysfs文件(如dev文件),用于udev根据sysfs文件系统下的dev文件创建设备节点
-
device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, GPIO_MINOR), 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);
-
class_destroy(gpio_class);
-
unregister_chrdev(GPIO_MAJOR, DEVICE_NAME);
-
}
-
-
module_init(gpio_init);
-
module_exit(gpio_exit);
-
MODULE_LICENSE("GPL");
-
MODULE_VERSION ("v2.0");
-
MODULE_AUTHOR("wbl <>");
- MODULE_DESCRIPTION("OMAPL138 GPIO driver");
相关推荐
变频器相关使用
想用变频器传动带有改善功率因数用电容器的电机,电机却不动,原因是:变频器的电流流入改善功率因数用的电容器,由于其充电电流造成变频器过电流(OCT),所以不能起动,作为对策,请将电容器拆除后运转,甚至改善功率因数,在变频器的输入侧接入AC电抗器是有效的。一般电机利用装在轴上的外扇或转子端环上的叶片进行冷却,若速度降低则冷却效果下降,因而不能承受与高速运转相同的发热,必须降低在低速下的负载转矩,或采用容量大的变频器与电机组合,或采用专用电机。电流型是将电流源的直流变换为交流的变频器,其直流回路滤波石电感。
linux驱动开发学习笔记十六:gpio相关OF函数和子系统API函数
一、gpio相关OF函数 我们在设备节点中会定义了一个名为“gpios”的属性,当然不一定是“gpios”,你可以自定义。gpios 属性描述了 test 这个设备所使用的 GPIO。在驱动程序中需要读取 gpios 属性内容,Linux 内核提供了几个与 GPIO 有关的 OF 函数,常用的几个 OF 函数如下所示: of_gpio_named_count 函数 of_gpio_named_...
GPIO(简介、IO端口基本结构、GPIO的八种模式、GPIO寄存器、通用外设驱动模型、GPIO配置步骤、编程实战)
GPIO(简介、IO端口基本结构、GPIO的八种模式、GPIO寄存器、通用外设驱动模型、GPIO配置步骤、编程实战)
使用gpio_direction_output()无法设置GPIO原因分析
3、通过逻辑分析仪抓到的波形分析可以看到,我们的driver是有一段时间把这个GPIO拉高的动作的,但是不久之后这个IO后就有一段很长的拉低拉高的波形,这个波形很像数据传输的波形,最后IO口被拉低,然后我们有理由怀疑这个IO口是和控制器冲突了,通过查看这个IO口可以知道GPIO3_D7在RK3399芯片中是I2S0控制器DATA0输出引脚。echo 1 > /sys/class/gpio/gpio127/value #设置GPIO3_D7输出高电平。linux 应用层操作GPIO。...
TMS320F28377D的sys/bios双核工程配置详解——从零搭建到RAM优化
本文详细解析了TMS320F28377D双核系统在sys/bios环境下的工程配置与RAM优化策略。从开发环境搭建、SYS/BIOS工程创建到双核CMD文件配置,提供了实战技巧和常见问题解决方案,帮助开发者高效实现电力电子控制系统中的双核协作与性能优化。
零、HarmonyOS应用开发者基础学习总览
零、HarmonyOS应用开发者基础学习总览
【正点原子STM32】GPIO(简介、IO端口基本结构、GPIO的八种模式、GPIO寄存器、通用外设驱动模型、GPIO配置步骤、编程实战)
GPIO的八种模式 输入浮空 F1系列 F4/F7/H7系列 作用:负责采集外部器件的信息或者控制外部器件工作,即输入输出 输入下拉 模拟功能 开漏输出 开漏式复用功能 输入上拉 推挽输出 推挽式复用功能 F4/F7/H7系列和F1系列的GPIO差异点 通用外设驱动模型(四步法) 1,初始化 时钟设置、参数设置、IO设置、中断设置(开中断、设NVIC)(可选) 2,读函数(可选) 从外设读取数据 3,写函数(可选) 往外设写入数据 4,中断服务函数(可选) 根据中断标志,处理外设各种中断事务
天池长期赛:二手车价格预测(422方案分享)
本次比赛是一次很好的锻炼数据挖掘能力的入门赛,从EDA-数据清洗-特征工程-模型调参-模型融合,能够完整的学习到大数据的分析和挖掘,值得历练。
GPIO的驱动模型
原文地址:GPIO的驱动模型 作者:wangbaolin719 一、概述 GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋
自动驾驶开发者必看:nuscenes数据集23类物体标注全解析(附避坑指南)
本文深入解析nuscenes数据集的23类物体标注系统,为自动驾驶开发者提供全面的标注规范解读和实战避坑指南。涵盖多模态数据组织、类别细分规则、属性系统应用技巧以及标注质量验证方法,帮助开发者高效利用这一标杆数据集提升模型性能。
等保测评-瀚高数据库
一般适用于等保测评
从裸机到Linux:GPIO驱动模型与libgpiod实战解析
在嵌入式系统开发中,GPIO(通用输入输出)是最基础且核心的硬件接口,它负责处理器与外部设备(如LED、按键、传感器)的直接交互。其工作原理是通过配置芯片引脚的电平状态(高/低)来实现数字信号的输入检测与输出控制,是嵌入式设备感知和控制物理世界的基石。GPIO的技术价值在于其通用性和灵活性,使得开发者能够通过软件编程灵活地定义硬件行为,从而连接和控制海量外部器件。在Linux操作系统环境下,GPIO的应用场景尤为广泛,从简单的LED闪烁、按键检测,到复杂的工业控制、物联网设备交互都离不开它。然而,与裸机开发
【雷达通信】雷达信号处理仿真【含Matlab源码 2509期】
雷达信号处理仿真 完整的代码,方可运行;可提供运行操作视频!适合小白!
通用外设驱动模型(四步法)及配置GPIO步骤
通用外设驱动模型四步法:初始化、读函数、写函数、中断服务函数。GPIO配置步骤及配置函数。
人工智能面试总结-分类与聚类
目录说说常用的分类算法,以及各自的优缺点?说说为什么正确率有时不能有效评估分类算法?说说什么样的分类器最好?说说聚类算法有哪些衡量标准?(选看)各聚类算法性能比较汇总说说什么是聚类,你知道哪些聚类算法?具体展开介绍你知道的聚类算法?说说K-Means聚类算法流程?说说K-Means聚类算法如何调优?说说K-Means聚类算法如何选择初始点?说说K-Means聚类聚的是特征还是样本?说说K-Means聚类的特征距离是如何计算的?说说聚类与分类的区别?手撕K-Means聚类 说说常用的分类算法,以及各自的优缺点
RT-DETR改进策略【Conv和Transformer】| HiLo注意力机制 通过分离处理图像的高频和低频信息,高效处理图像特征
本文记录的是利用改进检测模型,针对目标检测中面临的多尺度特征融合效率与长距离依赖建模难题,HiLo注意力模块的引入旨在通过频率解耦策略优化高分辨率特征处理,将高频细节(如目标边缘)与低频语义(如场景结构)分离建模,提升目标检测精度。Fast Vision Transformers with HiLo AttentionHiLo注意力模块的提出源于对传统自注意力机制局限性的反思。传统多头自注意力(MSA)在处理高分辨率图像时存在以下问题:HiLo将注意力模块分为高频(Hi-Fi)和低频(Lo-Fi)两个分支,
Linux下GPIO驱动模型
转载地址:http://blog.sina.com.cn/s/blog_5ef638bc0100rzve.html GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,当然你也可以选择不用这个模型实现gpio。具体见说明文档Documention/gpio.txt。 下面粗略说一下这个模型关键的数据结构和函数: 为了给不同GPIO控制器提供一个
IEM模型,地表粗糙度模拟
利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟
Linux 下 GPIO驱动模型
转载地址:http://blog.chinaunix.net/uid-27717694-id-3624294.html一、概述GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱
假人有限元模型
假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用
ET2012新版免狗免安装绿色软件
ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,
GPIO的驱动模型——linux
一、概述 GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋友应该比较熟悉寄存器级的驱动。 GPIO的驱动主要就是读取GPIO口的状
Devexpress16.2.6破解工具
Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具
linux 标准GPIO 驱动模型—version1
学习培训中
3958



被折叠的 条评论
为什么被折叠?



