Linux下s3c6410的GPIO操作(6)
2022-06-09 来源:eefocus
1、在 Linux下s3c6410的GPIO操作(3) 这篇博客中少分析了一个函数,当时列出了源码,但没分析,现在补上。
什么函数呢?如下所示:
#ifdef CONFIG_S3C_GPIO_CFG_S3C64XX
/**
* s3c_gpio_setcfg_s3c64xx_4bit - S3C64XX 4bit single register GPIO config.
* @chip: The gpio chip that is being configured.
* @off: The offset for the GPIO being configured.
* @cfg: The configuration value to set.
*
* This helper deal with the GPIO cases where the control register has 4 bits
* of control per GPIO, generally in the form of:
* 0000 = Input
* 0001 = Output
* others = Special functions (dependant on bank)
int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
unsigned int off, unsigned int cfg)
{
void __iomem *reg = chip->base;
得到GPIO端口控制寄存器的基地址,不同的端口可能不同哦!如下所示:
(第一种)、
static struct s3c_gpio_chip gpio_4bit[] = {
{
.base =S3C64XX_GPA_BASE,
.config = &gpio_4bit_cfg_eint0111,
.chip = {
.base = S3C64XX_GPA(0),
.ngpio = S3C64XX_GPIO_A_NR,
.label = 'GPA',
}
(第二种)
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',
}
(第三种)、
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',
}
既然端口分三种,那么对应的操作函数也应该分为三种,但实际上分成了两种,按控制寄存器的控制位数分为4和2.
这两种操作函数分别是s3c_gpio_setcfg_s3c64xx_4bit函数和s3c_gpio_setcfg_s3c24xx函数。
unsigned int shift = (off & 7) * 4;
u32 con;
if (off < 8 && chip->chip.ngpio > 8)
reg -= 4;
这个判断是为4-2这种情况准备的,因为上面的基地址是第二个控制寄存器的基地址,所以要减去4得到第一个控制寄存器的基地址。可以这样进行判断,一个很重要的原因就是下面这个表,观察一下,是否发现4Bit类型的都没有超过8个。所以我才说这个是针对4-2这种情况的。
/* GPIO bank summary:
*
* Bank GPIOs Style SlpCon ExtInt Group
* A 8 4Bit Yes 1
* B 7 4Bit Yes 1
* C 8 4Bit Yes 2
* D 5 4Bit Yes 3
* E 5 4Bit Yes None
* F 16 2Bit Yes 4 [1]
* G 7 4Bit Yes 5
* H 10 4Bit[2] Yes 6
* I 16 2Bit Yes None
* J 12 2Bit Yes None
* K 16 4Bit[2] No None
* L 15 4Bit[2] No None
* M 6 4Bit No IRQ_EINT
* N 16 2Bit No IRQ_EINT
* O 16 2Bit Yes 7
* P 15 2Bit Yes 8
* Q 9 2Bit Yes 9
*
* [1] BANKF pins 14,15 do not form part of the external interrupt sources
* [2] BANK has two control registers, GPxCON0 and GPxCON1
*/
if (s3c_gpio_is_cfg_special(cfg)) {
cfg &= 0xf;
cfg <<= shift;
}
#define s3c_gpio_is_cfg_special(_cfg)
(((_cfg) & S3C_GPIO_SPECIAL_MARK) == S3C_GPIO_SPECIAL_MARK)
#define S3C_GPIO_SPECIAL_MARK(0xfffffff0)
主要目的是为了判断传入的 unsigned int cfg这个参数,这个参数的之可以为0xfffffffx,其中x有下表所示:
当然,也可以传入的参数直接为上表中的数值,看开头的注释,就可以明白了。
con = __raw_readl(reg);
con &= ~(0xf << shift);
con |= cfg;
__raw_writel(con, reg);
这一部分很简单,无非就是读后,再写。
return 0;
}
注:如果大家对上面的shift的处理不是很明白,可以举个实际例子。如9的时候,unsigned int shift = (off & 7) * 4;的shift为1,别忘了现在是对第二个控制寄存器操作,0-7是第一个寄存器,8以后是第二个寄存器,那9就是第二个控制寄存器的第二个控制段,也就是第二个4位,这么说应该明白了吧。
#endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */
2、
上面说的是两个函数中的其中一个,现在来说第二个,s3c_gpio_setcfg_s3c24xx,源码如下:
/**
* s3c_gpio_setcfg_s3c24xx - S3C24XX style GPIO configuration.
* @chip: The gpio chip that is being configured.
* @off: The offset for the GPIO being configured.
* @cfg: The configuration value to set.
*
* This helper deal with the GPIO cases where the control register
* has two bits of configuration per gpio, which have the following
* functions:
* 00 = input
* 01 = output
* 1x = special function
*/
int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip,
unsigned int off, unsigned int cfg)
{
void __iomem *reg = chip->base;
unsigned int shift = off * 2;
u32 con;
if (s3c_gpio_is_cfg_special(cfg)) {
cfg &= 0xf;
if (cfg > 3)
return -EINVAL;
cfg <<= shift;
}
con = __raw_readl(reg);
con &= ~(0x3 << shift);
con |= cfg;
__raw_writel(con, reg);
return 0;
}
和上面那个函数一样,而且还相对简单,就不分析了。
- 学习ARM开发(2)
- Linux帧缓冲设备驱动程序框架及图形界面GUI的移植
- Linux Kernel之flush_cache_all在ARM平台下是如何实现的
- 手把手教你写Linux设备驱动---中断(三)--workqueue实现(基于友善之臂4412开发板)
- makefile初步制作,arm-linux- (gcc/ld/objcopy/objdump)详解
- Ubuntu下安装arm-linux-gnueabi-xxx编译器
- 用Qemu运行/调试arm linux
- Linux内核异常处理体系结构详解(一)
- arm linux 移植 mtd-utils 1.x
- 基于gnu-arm-linux的LPC2220的简单工程模板