历史上的今天
返回首页

历史上的今天

今天是:2024年12月03日(星期二)

正在发生

2021年12月03日 | iTOP-4412 开发板的 GPIO 是怎么操作的?

2021-12-03 来源:eefocus

Exynos4412 所有的 GPIO 都有固定的地址,为了方便操作这些 GPIO,Linux 内核

在 gpio-exynos4.h 里面定义了一些 GPIO 的宏,例如:

#define EXYNOS4_GPA0(_nr)  (EXYNOS4_GPIO_A0_START + (_nr)) 

#define EXYNOS4_GPA1(_nr)  (EXYNOS4_GPIO_A1_START + (_nr)) 

#define EXYNOS4_GPB(_nr)  (EXYNOS4_GPIO_B_START + (_nr)) 

..................................... 

#define EXYNOS4_GPY5(_nr)  (EXYNOS4_GPIO_Y5_START + (_nr)) 

#define EXYNOS4_GPY6(_nr)  (EXYNOS4_GPIO_Y6_START + (_nr)) 

#define EXYNOS4_GPZ(_nr)  (EXYNOS4_GPIO_Z_START + (_nr)) 

这些宏就是把每个 GPIO 的地址做了一下封装,它的好处就是方便我们使用并且

根据宏的名字就能直观的知道是在操作哪个 GPIO。

Linux 内核中关于 GPIO 的驱动在 driver/gpio/gpio-exynos4.c 文件里面, 在这

个文件中 GPIO 驱动初始化入口函数是 exynos4_gpiolib_init, 因为这个文件同

时也支持 4210 的 GPIO,所以开始先初始化了一些通用的 GPIO (4412 和 4210 都

有的 GPIO) ,代码如下:

chip = exynos4_gpio_common_4bit; 

nr_chips = ARRAY_SIZE(exynos4_gpio_common_4bit); 

for (i = 0; i < nr_chips; i++, chip++) { 

if (chip->config == NULL) 

chip->config = &gpio_cfg; 

if (chip->base == NULL) 

pr_err("No allocation of base address for [common gpio]"); 

samsung_gpiolib_add_4bit_chips(exynos4_gpio_common_4bit, 

nr_chips); 

变量 exynos4_gpio_common_4bit 是一个数组, 定义了一些通用的 GPIO, nr_chips

是记录的 exynos4_gpio_common_4bit 数组里面素个数。

首先使用 for 循环遍历 exynos4_gpio_common_4bit 所有的素,为每个素的

config 结构赋值:

if (chip->config == NULL) 

chip->config = &gpio_cfg; 

gpio_cfg 是类型为 s3c_gpio_cfg 的结构体,这个结构体的定义如下:

struct s3c_gpio_cfg { 

unsigned int  cfg_eint; 

s3c_gpio_pull_t  (*get_pull)(struct s3c_gpio_chip *chip, unsigned 

offs); 

int    (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs, 

s3c_gpio_pull_t pull); 

unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs); 

int  (*set_config)(struct s3c_gpio_chip *chip, unsigned offs, 

unsigned config); 

}; 

通过上面的代码我们可以看到这个结构体里主要是一些函数指针,get_pull 是

获取 GPIO 的上拉状态,set_pull 是设置 GPIO 上拉或下拉的,set_config 是设

置 GPIO 的工作模式,例如:输出/输入/其他功能。下面我们来看看 gpio_cfg

变量的定义,如下:

static struct s3c_gpio_cfg gpio_cfg = { 

.set_config  = s3c_gpio_setcfg_s3c64xx_4bit, 

.set_pull  = s3c_gpio_setpull_exynos4, 

.get_pull  = s3c_gpio_getpull_exynos4, 

}; 

通过上面的代码,可以看到分别对 gpio_cfg 结构的三个函数指针赋值,这三个

函数 的 定义 是在 gpio-config.c 里面 实现 的 , 这个 文 件 在 内核 源 码

arch/arm/plat-samsung 目录下,这三个函数的作用就是根据传进来的参数,配

置 GPIO 相应的寄存器,从而实现对 GPIO 的操作。

然后 我们 回到 gpio-exynos4.c , 接 着看 下 面 的代 码, 完成 了

exynos4_gpio_common_4bit 中每个素的 config 结构赋值后, 接着会调用函数

samsung_gpiolib_add_4bit_chips(exynos4_gpio_common_4bit,  nr_chips) 来

向系统注册 GPIO 结构体。代码如下:

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(chip) 和

s3c_gpiolib_add(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); 

这个函数也是为函数指针赋值,direction_input 是设置 GPIO 为输入模式,

direction_output 是设置 GPIO 为输出。

s3c_gpiolib_add(chip)函数主要作用是给一些函数指针赋值,然后根据传进来

的参数把对应的 GPIO 的信息保存到 gpio_desc 结构里,gpio_desc 是内核里面

定义的一个全局变量,用来保存每个 GPIO 的信息。 至此 GPIO 的驱动初始化就完

成了,其他它主要完成的功能就是为每个 GPIO 的结构体里面的函数指针赋值,

最后把每个 GPIO 结构信息保存到全局变量 gpio_desc 里面。

上面已经完成了一些通用的 GPIO 驱动的初始化,我们在回到 gpio-exynos4.c,

下面是根据 CPU 的型号初始化 CPU 特定的 GPIO 了,代码如下:

/* Only 4210 GPIO part */ 

if (soc_is_exynos4210()) { 

chip = exynos4210_gpio_4bit; 

nr_chips = ARRAY_SIZE(exynos4210_gpio_4bit); 

for (i = 0; i < nr_chips; i++, chip++) { 

if (chip->config == NULL) 

chip->config = &gpio_cfg; 

if (chip->base == NULL) 

pr_err("No allocation of base address [4210 gpio]"); 

samsung_gpiolib_add_4bit_chips(exynos4210_gpio_4bit, 

nr_chips); 

} else { 

/* Only 4212/4412 GPIO part */ 

chip = exynos4212_gpio_4bit; 

nr_chips = ARRAY_SIZE(exynos4212_gpio_4bit); 

for (i = 0; i < nr_chips; i++, chip++) { 

if (chip->config == NULL) 

chip->config = &gpio_cfg; 

if (chip->base == NULL) 

pr_err("No allocation of base address [4212 gpio]"); 

samsung_gpiolib_add_4bit_chips(exynos4212_gpio_4bit, 

nr_chips); 

通过看上面的代码,初始化过程与前面介绍的初始化通用 GPIO 原理是一样的,

这里我们不在细介绍。对所有 GPIO 的初始化完成以后内核中的其他驱动模块

就可以方便的使用我们注册到 gpio_desc 里面的 GPIO 了。内核提供了几个全局

函数来操作这些 GPIO:

int gpio_request(unsigned gpio, const char *label) 

void gpio_free(unsigned gpio) 

int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull) 

int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) 

int gpio_direction_input(unsigned gpio) 

int gpio_direction_output(unsigned gpio, int value) 

gpio_request 函数是申请 GPIO 操作, 根据传递进来的参数 gpio, 会去全局变量

gpio_desc 里面找到对应的 GPIO 结构,判断 desc 的标志位 flag 有没有被设置

FLAG_REQUESTED,如果有设置说明其他地方在使用这个 GPIO,程序返回-EBUSY

错误,如果没有设置就设置 flags 的标记为 FLAG_REQUESTED。

gpio_free 函数是释放 GPIO 操作,根据传递进来的参数,在 gpio_desc 全局变

量找到对应的 GPIO 结构,清除掉 desc 的 flag 标志变量的 FLAG_REQUESTED 位。

s3c_gpio_setpull 函数是设置 GPIO 的上拉或下拉的,变量 pull 的取值范围如

下定义:

#define S3C_GPIO_PULL_NONE  ((__force s3c_gpio_pull_t)0x00) 

#define S3C_GPIO_PULL_DOWN  ((__force s3c_gpio_pull_t)0x01) 

#define S3C_GPIO_PULL_UP  ((__force s3c_gpio_pull_t)0x02) 

S3C_GPIO_PULL_NONE 是悬空

S3C_GPIO_PULL_DOWN 是下拉

S3C_GPIO_PULL_UP 是上拉

s3c_gpio_cfgpin 函数是设置 GPIO 的功能:输入/输出/其他功能,第二个参数

config 取值范围如下:

#define S3C_GPIO_INPUT  (S3C_GPIO_SPECIAL(0)) 

#define S3C_GPIO_OUTPUT  (S3C_GPIO_SPECIAL(1)) 

#define S3C_GPIO_SFN(x)  (S3C_GPIO_SPECIAL(x)) 

S3C_GPIO_INPUT 是输入模式,S3C_GPIO_OUTPUT 是输出模式,S3C_GPIO_SFN(x)

是其他模式,例如中断模式等。

gpio_direction_input 函数设置 GPIO 是输入功能。

gpio_direction_output 设置 GPIO 输出,第二个参数 value 取值 0 或 1,0 代表

输出低电平,1 代表输出高电平。

下面我们来看几个 GPIO 操作的例子:

if (gpio_request(EXYNOS4_GPX3(3), "MPU6050 INT")) 

printk(KERN_WARNING  "MPU6050  INT(GPX3.3)  Port  request  error!!!n"); 

else{ 

s3c_gpio_setpull(EXYNOS4_GPX3(3), S3C_GPIO_PULL_NONE); 

s3c_gpio_cfgpin(EXYNOS4_GPX3(3), S3C_GPIO_SFN(0)); 

gpio_direction_input(EXYNOS4_GPX3(3)); 

gpio_free(EXYNOS4_GPX3(3)); 

上面的代码是设置 GPIO 引脚 GPX3_3 为输入模式,悬空。 

err = gpio_request_one(EXYNOS4_GPX0(0), GPIOF_IN, "mcp251x_INT"); 

if (err) { 

printk(KERN_ERR "failed to request mcp251x_INTn"); 

return -1; 

s3c_gpio_cfgpin(EXYNOS4_GPX0(0), S3C_GPIO_SFN(0xf)); 

s3c_gpio_setpull(EXYNOS4_GPX0(0), S3C_GPIO_PULL_NONE); 

gpio_free(EXYNOS4_GPX0(0)); 

上面的代码设置 GPIO 引脚 GPX0_0 为中断模式。

if(gpio_request(EXYNOS4_GPK1(0), "GPK1_0")) 

printk(KERN_ERR "failed to request GPK1_0 for " 

"USI controln"); 

return err; 

gpio_direction_output(EXYNOS4_GPK1(0), 1); 

s3c_gpio_cfgpin(EXYNOS4_GPK1(0), S3C_GPIO_OUTPUT); 

gpio_free(EXYNOS4_GPK1(0)); 

上面的代码设置 GPIO 引脚 GPK1_0 为输出模式,并且输出高电平。

iTOP-4412 的 GPIO 驱动就介绍到这里,大家有兴趣的话可以去内核里面细的

查看一下整个驱动的细实现。 


推荐阅读

史海拾趣

力芯微(ETEK)公司的发展小趣事

在2009至2012年的培育期,力芯微公司准确把握下游市场更迭,快速推出的双SIM卡电源控制芯片得到了三星电子的认可。此后,公司陆续开发了负载开关、电池开关和LDO等产品,并在三星电子的手机上得到广泛应用。这一合作不仅提升了力芯微在业界的知名度,也为公司带来了可观的订单和利润。

BTCPower公司的发展小趣事

随着全球环保意识的提高,绿色发展成为电子行业的重要趋势。BTCPower积极响应这一趋势,将绿色发展理念融入公司的产品和服务中。公司致力于研发更环保、更节能的产品,同时还推动供应链中的合作伙伴共同实现绿色生产。这些努力使得BTCPower在行业中树立了良好的环保形象。

富捷(FOJAN)公司的发展小趣事

富捷电子深知质量是企业生存和发展的基石。因此,公司高度重视质量管理体系建设,成功导入了ISO9001/IATF16949及VDA6.3质量管理体系、ISO14001环境管理体系。在原材料管理、产品生产、产品过程检验及出货流程中,公司严格遵循体系要求,秉持全面质量管理(TQM)精神,确保每一环节都达到国际最高品质标准。这种对质量的执着追求,赢得了客户的广泛信赖和好评。

GE Power Electronics Inc公司的发展小趣事
合理设计电路布局和布线,避免信号干扰和串扰。同时,采用适当的保护电路,如过压保护、过流保护等。
Curtis Industries公司的发展小趣事

为了进一步扩大市场份额,Curtis Industries公司积极拓展市场布局。公司在全球范围内设立了多个生产基地和研发中心,以便更好地满足不同地区客户的需求。同时,公司还加强了与上下游企业的合作,形成了完整的产业链。这些举措不仅提升了公司的产能和研发实力,还为公司带来了更多的商业机会。

ECLIPTEK公司的发展小趣事

随着全球对环保问题的日益关注,ECLIPTEK公司积极响应环保号召,将绿色环保理念融入其产品研发和生产过程中。公司采用环保材料和清洁能源,减少生产过程中的废弃物和污染物排放。同时,ECLIPTEK还积极参与环保公益活动,推动电子行业的可持续发展。

问答坊 | AI 解惑

射频和微波开关测试系统基础

无线通信产业的巨大成长意味着对于无线设备的元器件和组件的测试迎来了大爆发,包括对组成通信系统的各种RF  IC 和微波单片集成电路的测试。这些测试通常需要很高的频率,普遍都在GHz范围。本文讨论了射频和微波开关测试系统中的关键问题 ...…

查看全部问答>

求好心人帮忙pudn下个2410上的U盘代码

http://www.pudn.com/downloads100/sourcecode/embed/detail410820.html 哪位有帐号的好心人下来 发到我邮箱:carrot_shi@yahoo.com.cn 先谢过!!…

查看全部问答>

s3c2440 800x600 如何提速控件显示速度

本人初学wince,请教大虾们一个问题。 本人使用的是S3c2440,wince5.0,800x600的LCD。 因为屏幕过大,wince的显示看起来已经较慢。 因为客户的要求,开发软件需要保持与pc机版本的界面一致。导致程序中需要在一个界面上绘制上百个控件,可以看 ...…

查看全部问答>

手机内存卡原文件夹都变成了后缀ink格式,在手机里打不开,只有在电脑上才能打开是什么原因

手机内存卡原文件夹都变成了后缀ink格式,在手机里打不开,只有在电脑上才能打开是什么原因…

查看全部问答>

PCB布线1(差分线)

布差分线时,两条线的长度要尽量的一样长、两条线的间距要尽可能的近,两条线要保持平行,越早平行越好。那么,如何走平行线呢?有两种方法:两条线走在同一走线层,两条线走在上下相邻的两层。不过,一般是走在同一走线层。 下面是有用的资料: ...…

查看全部问答>

can拨特率计算?

我算的怎么和例子上的不一样啊?例子上的100KBPS/S:设置如下(用的外部晶振(是8M的吗?),SYSCLK是HSE,CAN时钟应该是4M吧!  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;  CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;  ...…

查看全部问答>

"Cannot load flash programming Algorithm"错误,怎么整!!!

我的板子是9b92 用的是ulink2 +keil 4.10    程序编译没有问题,ulink也没有问题,就是下载的时候失败,这个是相关的设置页面,大家帮忙看一下,相当的着急上火啊!   [ 本帖最后由 bonnypro 于 2011-5-16 12:27 编辑 ]…

查看全部问答>

请问如何提取接收到的字字符数据

Z-stack文件夹里的SerialApp这个例程中,接收节点发过来的信息并转给串口是UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )函数里的下面语句:      case AF_INCOMING_MSG_CMD:    & ...…

查看全部问答>

A7103芯片做的rf模块看上去还不错,为什么没有卖的?

A7103芯片做的rf模块看上去还不错,为什么没有卖的?…

查看全部问答>