本帖最后由 arthur 于 2023-8-14 13:52 编辑
查阅NUC980 TRM手册
PA.2 是一个multifunction PIN
MFP = 0 为普通的GPIO功能
MFP = 1 为UART6_CTS
MFP = 2 为I2S_LRCK
MFP = 3 为SC0_CD
MFP = 4 为JTAG1_TDO
MFP = 6 为TM2_ECNT
jtag0组下属的pins有PG11, PG12, PG13, PG14, PG15, pin number分别为0x02, 0x03, 0x04, 0x05, 0x06
jtag1组下属的pins有PA2, PA3, PA4, PA5, PA6, pin number分别为0x6B, 0x6C, 0x6D, 0x6E, 0x6F
文件 pinctrl-nuc980.c,数组nuc980_pinctrl_groups[] 里,
{
.name = "jtag1_grp",
.pins = jtag1_pins,
.num_pins = ARRAY_SIZE(jtag1_pins),
.func = 0x4,
},
从NUC980 TRM page 62查到
.func = 0x7时,JTAG0作为JTAG使用
.func = 0x4时,JTAG1作为JTAG使用
如果想把JTAG1所占用的IO口作为普通的GPIO来使用的话,就需要将 .func = 0x0
现在来分析结构体 struct nuc980_pinctrl_group.func 是如何通过nuc980_set_mux()对.func来区分不同组(group)下的各个PIN的功能。
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;
offset = (j >> 4)*8 + ((j & 0x8) ? 4 : 0);
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;
}
nuc980_set_mux() 首先取得各个组(jtagX group)下的每个pin, 对每个pin_num 作如下运算,计算出其相对于REG_MFP_GPA_L的偏移offset
offset = (pin_num >> 4) * 8 + ((pin_num & 0x8) ? 4 : 0;
读出每一个pin_num的寄存器的值:reg = __raw_readl(REG_MFP_GPA_L + offset); 在此值的基础上,再将多功能PIN的值附加上去
reg = (reg & ~ (0xF << ((pin_num & 0x7) * 4))) | (nuc980_pinctrl_groups[group].func << ((pin_num & 0x7) * 4));
“在此值的基础上,再将多功能PIN的值附加上去”,这里至关重要,也很神密,它是如何做到简单地配置一下.func 就能将“一组group下的所有pin作为单一的功能”的呢?
|