在通过GPIO模拟I2C时序的问题,要用到PG11这个引脚,而这个引脚默认是JTAG0的TDO,所在在加载ko模块时,会现现
# echo 203 > export
[***liuyouhua-debug***] offset: 203 group: 6 numl: 11 num: 3 value: 0x7
Please Check GPIOG11's multi-function = 0x7
注:203是PG11对应的CPU引脚封装号,定义在$(KERN-DIR)/arch/arm/mach-nuc980/include/mach/gpio.h中:
#define NUC980_PG11 (0xC0 + 11)
#define NUC980_PG12 (0xC0 + 12)
#define NUC980_PG13 (0xC0 + 13)
#define NUC980_PG14 (0xC0 + 14)
#define NUC980_PG15 (0xC0 + 15)
通过跟踪内核代码发现,PG11没有得到$(KERN-DIR)/drivers/pinctrl-nuc980.c里nuc980_set_mux函数的处理:
/*
* selector = data.nux.func, which is entry number in nuc980_functions,
* and group = data.mux.group, which is entry number in nuc980_pmx_func
* group is not used since some function use different setting between
* different ports. for example UART....
*/
int nuc980_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
unsigned group)
{
unsigned int i, j;
unsigned int reg, offset;
for(i = 0; i < nuc980_pinctrl_groups[group].num_pins; i++) {
j = nuc980_pinctrl_groups[group].pins[i];
offset = (j >> 4) * 8 + ((j & 0x8) ? 4 : 0); //计算j在REG_MFP_GPX定义中的偏移
reg = __raw_readl(REG_MFP_GPA_L + offset);
reg = (reg & ~(0xF << ((j & 0x7) * 4))) | (nuc980_pinctrl_groups[group].func << ((j & 0x7) * 4));
__raw_writel(reg, REG_MFP_GPA_L + offset);
}
return 0;
}
const struct pinctrl_pin_desc nuc980_pins[] = {
//......
PINCTRL_PIN(0x6B, "PG11"),
PINCTRL_PIN(0x6C, "PG12"),
PINCTRL_PIN(0x6D, "PG13"),
PINCTRL_PIN(0x6E, "PG14"),
PINCTRL_PIN(0x6F, "PG15"),
};
static const unsigned jtag0_pins[] = {0x6B, 0x6C, 0x6D, 0x6E, 0x6F};
static const struct nuc980_pinctrl_group nuc980_pinctrl_groups[] = {
//......
{
.name = "jtag0_grp",
.pins = jtag0_pins,
.num_pins = ARRAY_SIZE(jtag0_pins),
.func = 0x7,
},
//......
};
#define REG_MFP_GPA_L (GCR_BA+0x070) /* GPIOA Low Byte Multiple Function Control Register */
#define REG_MFP_GPA_H (GCR_BA+0x074) /* GPIOA High Byte Multiple Function Control Register */
#define REG_MFP_GPB_L (GCR_BA+0x078) /* GPIOB Low Byte Multiple Function Control Register */
#define REG_MFP_GPB_H (GCR_BA+0x07C) /* GPIOB High Byte Multiple Function Control Register */
#define REG_MFP_GPC_L (GCR_BA+0x080) /* GPIOC Low Byte Multiple Function Control Register */
#define REG_MFP_GPC_H (GCR_BA+0x084) /* GPIOC High Byte Multiple Function Control Register */
#define REG_MFP_GPD_L (GCR_BA+0x088) /* GPIOD Low Byte Multiple Function Control Register */
#define REG_MFP_GPD_H (GCR_BA+0x08C) /* GPIOD High Byte Multiple Function Control Register */
#define REG_MFP_GPE_L (GCR_BA+0x090) /* GPIOE Low Byte Multiple Function Control Register */
#define REG_MFP_GPE_H (GCR_BA+0x094) /* GPIOE High Byte Multiple Function Control Register */
#define REG_MFP_GPF_L (GCR_BA+0x098) /* GPIOF Low Byte Multiple Function Control Register */
#define REG_MFP_GPF_H (GCR_BA+0x09C) /* GPIOF High Byte Multiple Function Control Register */
#define REG_MFP_GPG_L (GCR_BA+0x0A0) /* GPIOG Low Byte Multiple Function Control Register */
#define REG_MFP_GPG_H (GCR_BA+0x0A4) /* GPIOG High Byte Multiple Function Control Register */
#define REG_MFP_GPH_L (GCR_BA+0x0A8) /* GPIOH Low Byte Multiple Function Control Register */
#define REG_MFP_GPH_H (GCR_BA+0x0AC) /* GPIOH High Byte Multiple Function Control Register */
#define REG_MFP_GPI_L (GCR_BA+0x0B0) /* GPIOI Low Byte Multiple Function Control Register */
#define REG_MFP_GPI_H (GCR_BA+0x0B4) /* GPIOI High Byte Multiple Function Control Register */
#define REG_MFP_GPJ_L (GCR_BA+0x0B8) /* GPIOJ Low Byte Multiple Function Control Register */
#define REG_DDR_DS_CR (GCR_BA+0x0E0) /* DDR I/O Driving Strength Control Register */
#define REG_PORDISCR (GCR_BA+0x100) /* Power-On-Reset Disable Control Register */
#define REG_ICEDBGCR (GCR_BA+0x104) /* ICE Debug Interface Control Register */
#define REG_WRPRTR (GCR_BA+0x1FC) /* Register Write-Protection Control Register */
实例解析PG11:
在驱动模块内,自己封装GPIO的set_mux,如:
int nuc980_gpio_set_mux(unsigned int gpio_num)
{
unsigned int reg, offset;
offset = (gpio_num >> 4) * 8 + ((gpio_num & 0x8) ? 4 : 0); //计算j在REG_MFP_GPX定义中的偏移
reg = __raw_readl(REG_MFP_GPA_L + offset);
reg = (reg & ~(0xF << ((gpio_num & 0x7) * 4))) | (0x0 << ((gpio_num & 0x7) * 4));
__raw_writel(reg, REG_MFP_GPA_L + offset);
return 0;
}
PINCTRL_PIN(0x6B, "PG11"),
PINCTRL_PIN(0x6C, "PG12"),
PINCTRL_PIN(0x6D, "PG13"),
PINCTRL_PIN(0x6E, "PG14"),
PINCTRL_PIN(0x6F, "PG15"),
nuc980_gpio_set_mux(0x6B);