本帖最后由 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作为单一的功能”的呢? 
 
 
 
 
 |